Troubleshooting
Run omac doctor first — it checks all prerequisites and prints the fix for whatever it finds.
omac doctor
- OS keychain: pings the keychain backend (Keychain on macOS, Secret Service on Linux)
- Launcher config: validates the launcher config file if one exists
- Skill registry: loads registered skills with sidecars and checks each one: is a binary/script present, are required secrets present?
- Inner harnesses: reports which harness CLIs (
opencode,claude, …) are onPATH - Built-in skills: checks whether
omac-write-a-skillis provisioned for each installed harness - Sandbox backend: checks the platform sandbox binary (
sandbox-execon macOS,bwrapon Linux) and warns if the network prompt dialog (osascript / zenity / kdialog) is missing - Sandbox profile: warns about broad filesystem grants that weaken isolation
Common errors
dial unix /run/user/1000/bus — no Secret Service provider found (WSL2)
Secret Service is the Linux standard for secure credential storage, accessed over D-Bus. WSL2 does not run the required daemon by default.
dial unix /run/user/1000/bus: connect: no such file or directory
no Secret Service provider found
Cause: gnome-keyring is not running; WSL2 has no Secret Service by default.
Fix: follow the WSL2 keychain setup in Installation → WSL2 (Ubuntu).
chmod temp: operation not permitted (WSL2)
chmod <tmpdir>: operation not permitted
Cause: the working directory is on an NTFS mount (/mnt/c/), which does not support Unix permissions.
Fix: move your repo to the native WSL2 filesystem.
mv /mnt/c/path/to/repo ~/projects/repo
cd ~/projects/repo
bubblewrap (bwrap): permission denied (AppArmor, Ubuntu 23.10+)
bwrap: No permissions to creating new namespace, likely because the kernel does not allow non-privileged user namespaces
Cause: Ubuntu 23.10+ restricts unprivileged user namespaces by default (kernel.apparmor_restrict_unprivileged_userns=1).
Fix: grant a one-time AppArmor exception — see Installation → Linux (Debian / Ubuntu).
unregistered skills found
omac start: unregistered skills found in this workdir:
<skill-name> — register with: omac register <skill-name>
...
To start without them for now (they will not run), add --skip-unregistered: omac start --skip-unregistered
Cause: the skill directory exists but omac register was never run for it.
Fix:
omac register <skill-name>
To start without the skill for now, pass --skip-unregistered. omac prints a
warning and runs without that skill's sidecar, secrets and install script. The
built-in sandbox hides the skill's folder only if its content is not host-approved.
Previously approved, unchanged content stays visible to the agent, even when the
skill is unregistered. Other backends do not hide skill content. The skip is
recorded in the audit log (route.state, skipped-unregistered):
omac start --skip-unregistered
exec: node: executable file not found in $PATH
exec: "node": executable file not found in $PATH
exec: "<harness>": executable file not found in $PATH
Cause: the inner harness binary is not installed or not on PATH.
Fix: install the missing harness — see Supported harnesses.
Harness hangs or BunInstallFailedError on WSL2
omac start: BunInstallFailedError
Symptoms on WSL2: omac start fails with BunInstallFailedError, or the harness hangs on start or during its login flow. omac doctor reports the harness as found, so the binary looks fine.
Cause: WSL2 is running a Windows-installed harness instead of a Linux one. If you also develop on Windows, your Windows PATH is visible inside WSL, so a harness installed on Windows (for example under /mnt/c/Users/.../AppData/Roaming/npm/) can be picked up by mistake. omac doctor cannot detect this — it only checks that the binary is on PATH, not which platform it was built for.
Fix: check where the harness resolves, and reinstall it natively inside WSL if it points into /mnt/c/.
Agent cannot authenticate with its AI provider
The harness starts but every model call fails with an authentication or missing-API-key error.
Cause: the sandbox only receives environment variables on the allow_vars list. Two common misconfigurations:
allow_varsis empty — this fails closed (nothing passes through), not open.- The harness reads its API key from an environment variable that is not allow-listed. claude-code, codex, and copilot auto-forward their provider keys automatically; the multi-provider harnesses — opencode, pi, and codewhale — do not, so you must add the variable yourself.
Fix: add the variable to allow_vars in ~/.config/omac/sandbox-profiles/default.json. See Configuration.
Copilot fails against a bring-your-own-key provider with request/validation errors
The COPILOT_* variables are forwarded by omac automatically (provider type,
base URL, API key, model, wire format), so a BYO-key copilot works under the
sandbox. If the provider rejects the requests themselves, the usual suspect is
the wire format GitHub Copilot picks: many OpenAI-compatible gateways only
serve chat/completions reliably, and copilot defaults to the OpenAI
Responses API (responses).
Fix: export COPILOT_PROVIDER_WIRE_API=completions before omac start copilot
— it is in the auto-forwarded set, so no profile change is needed. The full
variable set is documented by copilot help providers.
Copilot: Failed to extract bundled package: EPERM ... mkdir '.../Library/Caches/copilot/pkg/...'
The standalone copilot binary (for example the Homebrew cask) unpacks its
bundled package on first start. By default it unpacks into the OS user cache
dir, e.g. ~/Library/Caches/copilot on macOS. omac keeps that dir out of
reach of the agent on purpose, so the unpack fails. Copilot reads the target
from COPILOT_CACHE_HOME, not from TMPDIR.
Fix: update omac. Current builds set COPILOT_CACHE_HOME to copilot's config
home (~/.copilot, or $COPILOT_HOME), which the sandbox already grants. If
you cannot update, add ~/Library/Caches/copilot to filesystem.allow in
your sandbox profile. Running copilot once outside the sandbox does not help,
because the sandbox cannot read that cache dir either.
claude-code exits silently on macOS (no output, no model calls)
The claude process starts and exits with status 0 within a second. It prints nothing, makes no model call, and leaves no error message.
Cause: claude-code keeps its per-session temp files under
/tmp/claude-<uid> by default. It reads CLAUDE_CODE_TMPDIR if set, but
does not consult TMPDIR. omac's macOS sandbox grants a private
scratch directory instead of /tmp, so claude cannot create its temp
directory and stops silently. On Linux the sandbox provides its own
writable /tmp, which is why the same setup works there.
Fix: update omac. Current builds point CLAUDE_CODE_TMPDIR at the
sandbox scratch directory when launching claude-code, so no configuration
is needed. If you cannot update, granting /private/tmp write access in
your profile's filesystem.write works as a workaround — but that makes
the shared host temp directory writable for the agent and weakens the
default hardening, so prefer the update.
zsh: can't create temp file for here document: operation not permitted
Every zsh heredoc (cat <<EOF) and here-string (cat <<< text) fails
inside the macOS sandbox. zsh writes their content to a temp file named
after TMPPREFIX, which defaults to /tmp/zsh, and the macOS sandbox does
not grant /tmp.
Fix: update omac. Current builds set TMPPREFIX to $TMPDIR/zsh on macOS.
A TMPPREFIX you set yourself is kept if your profile's allow_vars lets
it through and it points into a writable directory. If you cannot update,
run export TMPPREFIX="$TMPDIR/zsh" inside the session.
An MCP server or other harness-launched tool cannot reach its token or open its port
The harness (opencode, claude-code, …) launches MCP servers inside the sandbox, so the MCP server is limited by the sandbox restrictions. Two things commonly need granting:
- A missing token. The tool reads an API token from an environment variable that is not allow-listed. Fix: add the variable name to
environment.allow_varsand export it beforeomac start. This means that the agent can also access your token! Alternatively, you can define a skill for MCP access. - A blocked local port. The tool opens a local port that the sandbox blocks by default. Fix: add the port to
network.open_port, or passomac start --open-port <port>(if you want to open the port only for the current session). A blocked loopback port is enforced by the kernel and leaves no entry in the audit trail, so it does not show up as a denied connection inomac diagnose. To check a specific port, runomac diagnose --probe 127.0.0.1:<port>, which reports whetheropen_portcurrently allows it.
See Running an MCP server the harness launches for a combined example.
Gradle build hangs, cannot reach its daemon, or cannot start a daemon
Cause: the Gradle daemon talks to its client over a random loopback port, which the sandbox's default kernel network enforcement blocks.
Fix: run Gradle without the daemon — ./gradlew --no-daemon (or set org.gradle.daemon=false). If Gradle still tries to start a daemon, align the JVM arguments with the project (see the Gradle documentation; the Single-use Daemon case must be prevented).
On macOS only, if you must keep the daemon, you can grant loopback with "network": { "open_port": [0] } in the sandbox grants file (~/.config/omac/sandbox-profiles/default.json) — 0 means "any loopback port" and external TCP egress stays kernel-blocked. On Linux there is no equivalent that keeps kernel enforcement, so use --no-daemon.
Undo a network allow/deny decision
When you answer the network prompt, "session" decisions are held in memory only, while "permanent" decisions are written to sandbox-profiles/default.pages.json.
- Session decision: restart
omac start— session decisions never persist and cannot be edited from a file, so a restart clears them. - Permanent decision: remove the entry from
~/.config/omac/sandbox-profiles/default.pages.json.
Reporting a bug
If omac doctor and the fixes above don't resolve your problem, please report it
as a GitHub issue at
github.com/TNG/oh-my-agentic-coder/issues.
Before opening one:
- Search first. Look through the existing issues for your problem. If you find a match, add your details there instead of opening a duplicate.
- Use the issue template. The "New issue" form guides you through the fields we need — a short summary, what went wrong, and how to reproduce it.
- Include your environment. Paste the output of
omac doctor, your OS and version, and the harness you were running (for exampleclaude-codeon Ubuntu 24.04).
Keep it concise. The collaboration guide has the full set of expectations for issue formatting.