---
title: Troubleshooting
description: Common issues and solutions when using nono
---

## Permission Denied Errors

### Symptom

Command fails with "Permission denied" or "Operation not permitted" errors.

### Diagnosis

1. **Check what access was granted**:
   ```bash
   nono run --allow-cwd --dry-run -- command
   ```

2. **Query capabilities from inside the sandbox**:
   ```bash
   # Check if a specific path is accessible
   nono run --allow-cwd -- nono why --self --path /tmp --op write --json

   # Human-readable output
   nono run --allow-cwd -- nono why --self --path ~/.ssh --op read
   ```

3. **Run with verbose logging**:
   ```bash
   nono run -vvv --allow-cwd -- command
   ```

### Common Causes

| Cause | Solution |
|-------|----------|
| Path not in allowed list | Add path with `--allow`, `--read`, or `--write` |
| Sensitive path blocked | Use `--bypass-protection` with your grant (see below) |
| Relative path resolved differently | Use absolute paths |
| Symlink target outside sandbox | Grant access to the symlink target |

### Sensitive Paths

These paths are blocked by default, even if a parent directory is allowed:

- `~/.ssh/` - SSH keys
- `~/.aws/` - AWS credentials
- `~/.gnupg/` - GPG keys
- `~/.kube/` - Kubernetes config
- `~/.docker/` - Docker credentials
- Shell history files
- Shell configuration files

**Why?** These paths commonly contain secrets that an AI agent should never access.

If you grant one of these paths with `--allow`, nono will warn you on macOS:

```
WARN '~/.gnupg' is blocked by 'deny_credentials'; use --bypass-protection ~/.gnupg to allow access
```

To intentionally access a blocked path, use `--bypass-protection` alongside your grant:

```bash
nono run --allow ~/.gnupg --bypass-protection ~/.gnupg -- gpg --list-keys
```

---

## Network Connection Failed

### Symptom

Commands like `curl`, `wget`, or API calls fail with connection errors.

### Possible Causes

1. **Network explicitly blocked** - You used `--block-net` flag
2. **Actual network issue** - DNS, firewall, or connectivity problem
3. **Application-specific issue** - App needs specific configuration

### Solutions

1. **If you used `--block-net`, remove it**:
   ```bash
   # Network is allowed by default
   nono run --allow-cwd -- curl https://example.com
   ```

2. **Check if network is allowed from inside the sandbox**:
   ```bash
   nono run --allow-cwd -- nono why --self --host example.com --json
   # Should show {"status":"allowed",...}
   ```

3. **Test network outside nono**:
   ```bash
   curl https://example.com
   # If this fails, it's not a nono issue
   ```

---

## Command Not Found

### Symptom

```
nono: command not found
```

or

```
error: No such file or directory: my-command
```

### Solutions

1. **nono not in PATH**:
   ```bash
   # Add to PATH
   export PATH="$PATH:/path/to/nono/target/release"
   ```

2. **Target command not in PATH**:
   ```bash
   # Use absolute path
   nono run --allow-cwd -- /usr/local/bin/my-command

   # Or ensure PATH is set correctly
   nono run --allow-cwd -- sh -c 'which my-command'
   ```

---

## Sandbox Initialization Failed

### Symptom

```
Error: Sandbox initialization failed: ...
```

### Linux (Landlock)

1. **Check kernel version**:
   ```bash
   uname -r
   # Must be 5.13+ for Landlock
   ```

2. **Check Landlock is enabled**:
   ```bash
   cat /sys/kernel/security/lsm
   # Should include "landlock"
   ```

3. **Enable Landlock** (if missing):
   Add `lsm=landlock,...` to kernel boot parameters

### macOS (Seatbelt)

1. **Check macOS version**:
   ```bash
   sw_vers
   # Should be 10.15 (Catalina) or later
   ```

2. **Check for SIP issues**:
   Some system integrity protection settings can interfere. This is rare.

---

## Dry Run Shows Different Paths

### Symptom

Paths in dry-run output don't match what you specified.

### Explanation

nono canonicalizes all paths:

- Relative paths become absolute
- Symlinks are resolved
- `..` and `.` are normalized

This is intentional to prevent symlink escape attacks.

### Example

```bash
$ pwd
/home/user/project

$ nono run --allow-cwd --dry-run -- command
Capabilities:
  [rw] /home/user/project    # Resolved from "."
```

---

## Child Process Doesn't Inherit Sandbox

### Symptom

You expect a child process to be sandboxed but it seems to have more access.

### This Shouldn't Happen

Child processes always inherit sandbox restrictions. If you're seeing this:

1. **Verify the parent is sandboxed**:
   ```bash
   # The --self flag only works inside a sandbox
   nono run --allow-cwd -- nono why --self --path /etc --op read
   # Should show current sandbox capabilities
   ```

2. **Check if you're testing correctly**:
   ```bash
   # Parent and child are BOTH sandboxed
   nono run --allow-cwd -- sh -c 'sh -c "cat /etc/passwd"'
   # Should fail if /etc is not allowed
   ```

If you have a reproducible case where a child escapes the sandbox, please report it as a security issue.

---

## Performance Issues

### Symptom

Commands run slower under nono.

### Explanation

There is minimal overhead from sandbox initialization (microseconds). If you're seeing significant slowdowns:

1. **First run may be slower** due to path canonicalization
2. **Many file operations** may show overhead from kernel permission checks

### Solutions

- Grant access to larger directories instead of many individual files
- Use `--read` for directories that don't need write access (slightly faster path)

---

## Using `nono why --self` for Debugging

When running inside a nono sandbox, you can query your own capabilities using `nono why --self`:

```bash
# Check if a path would be readable
nono run --allow-cwd -- nono why --self --path ~/.ssh --op read
# Output: DENIED - sensitive_path (SSH keys and config)

# Check if a path would be writable
nono run --allow . -- nono why --self --path ./src --op write
# Output: ALLOWED - Granted by: --allow .

# JSON output for programmatic use (useful for AI agents)
nono run --allow-cwd -- nono why --self --path /tmp --op write --json
# {"status":"denied","reason":"not_in_allowed_paths","suggestion":"--write /tmp"}

# Check network status
nono run --allow-cwd -- nono why --self --host api.openai.com
# Output: ALLOWED - network allowed by default

# Check network when blocked
nono run --allow-cwd --block-net -- nono why --self --host api.openai.com
# Output: DENIED - network_blocked
```

<Note>
The `--self` flag reads the sandbox state from `NONO_CAP_FILE`, which is the only environment variable nono sets. This is designed for programmatic introspection by AI agents rather than debugging via shell variables.
</Note>

---

## Platform-Specific Issues

### macOS: "killed: 9" or Immediate Termination

This usually means the Seatbelt profile was malformed. Run with `-vvv` to see the generated profile:

```bash
nono run -vvv --allow-cwd -- command
```

### Linux: "Landlock not supported"

Your kernel may not have Landlock enabled. Check:

```bash
# Verify kernel version
uname -r

# Check LSM list
cat /sys/kernel/security/lsm
```

### Linux: Network Restrictions Not Working

Network filtering requires Landlock ABI v4 (kernel 6.7+):

```bash
# Check kernel version
uname -r

# If < 6.7, network filtering is unavailable via Landlock
```

---

## Using `nono learn` to Discover Required Paths

If you're getting permission errors and aren't sure which paths your application needs, use `nono learn` on Linux or run the command under the target profile on macOS:

```bash
# Linux: discover all paths accessed by your app
nono learn -- my-app

# Linux: compare against an existing profile to see what's missing
nono learn --profile my-profile -- my-app

# Linux: output as JSON for easy profile creation
nono learn --json -- my-app

# macOS: collect real Seatbelt denials and offer to save a profile patch
nono run --profile my-profile -- my-app
```

<Note>
  On Linux, `nono learn` requires `strace` and runs without sandbox restrictions. On macOS, prefer sandboxed `nono run`; legacy unsandboxed tracing is still available with `nono learn --trace` and requires `sudo` for `fs_usage` and `nettop`.
</Note>

### Example Workflow

1. Run the command to discover paths:
   ```bash
   nono run --profile opencode -- opencode
   ```

2. Review the output to see which paths are needed:
   ```
   Read paths needed:
     /usr/share/locale-langpack
     /home/user/.config/opencode

   Write paths needed:
     /home/user/.cache/opencode
   ```

3. Add the paths to your nono command or profile:
   ```bash
   nono run --read /usr/share/locale-langpack --allow ~/.config/opencode -- opencode
   ```

---

## WSL2-Specific Issues

### Sandbox initialization: EBUSY on seccomp

**Symptom:** `Sandbox initialization failed` with `EBUSY` when using `--capability-elevation`.

**Cause:** WSL2's init process (PID 1) installs its own seccomp user notification filter. The Linux kernel only allows one notify listener per filter chain, so nono's attempt to install a second returns `EBUSY`.

**Solution:** nono automatically disables capability elevation on WSL2. If you see this error, ensure you're running a recent version. This is tracked in [microsoft/WSL#9548](https://github.com/microsoft/WSL/issues/9548).

### Credential proxy refused on WSL2

**Symptom:** `WSL2: proxy-only network mode cannot be kernel-enforced`

**Cause:** The proxy's network lockdown depends on seccomp notify or Landlock V4, neither of which is available on WSL2.

**Solutions:**
- Use `--env-credential` instead of `--credential` (env var injection works normally)
- Opt in to degraded proxy mode with `wsl2_proxy_policy: "insecure_proxy"` in your profile's security config ([details](/cli/internals/wsl2#credential-proxy-on-wsl2))

### Per-port network filtering unavailable

**Symptom:** `--open-port` or `--listen-port` fails on WSL2.

**Cause:** Landlock V4 (kernel 6.7+) is required for TCP port filtering. WSL2 ships kernel 6.6.

**Solution:** Use `--block-net` for full network isolation, or wait for a WSL2 kernel upgrade to 6.7+.

### Verifying WSL2 compatibility

Run `nono setup --check-only` inside WSL2 to see the full feature availability matrix:

```bash
nono setup --check-only
```

This reports the detected kernel version, Landlock ABI, WSL2 detection status, and which features are available.

---

## Getting Help

If you're still stuck:

1. **Search existing issues**: [GitHub Issues](https://github.com/always-further/nono/issues)
2. **Open a new issue** with:
   - nono version (`nono --version`)
   - OS and kernel version
   - Full command that failed
   - Error message
   - Output of `nono run --dry-run` with same flags
