Common problems when installing, configuring, running, or using Catalyst Code, organized by symptom.
Likely causes: The install script tries to write to /usr/local/bin/ or
/opt/catalyst-code/ without the required permissions.
Check:
- Run with
--dry-runfirst to see the planned paths:curl -fsSL https://raw.githubusercontent.com/catalystctl/catcode/refs/heads/master/install.sh | bash -s -- --dry-run - Check whether
/usr/local/binis writable.
Fix:
- Install with
--prefixto use a user-local directory:curl -fsSL ... | bash -s -- --prefix ~/.local/bin
- Or run as root (not recommended — prefer the prefix approach).
Likely cause: The install prefix is not in PATH.
Linux / macOS — Check:
- Run
which catcodeorcatcode --version. - Check the prefix used during installation (default:
/usr/local/bin).
Linux / macOS — Fix:
- Add the install prefix to your
PATH:Add the line toexport PATH="/usr/local/bin:$PATH"
~/.bashrc,~/.zshrc, or equivalent.
Windows — Check:
- Open a new terminal window (PowerShell, Command Prompt, or Windows Terminal)
after install — the current session keeps the old
PATH. - PowerShell:
Get-Command catcode,$env:Path -split ';' | Select-String catcode - CMD:
where catcodeandecho %PATH% - Default install dir:
%LOCALAPPDATA%\Programs\catcode\catcode.exe
Windows — Fix:
- Launch a new terminal, or run the full path once:
& "$env:LOCALAPPDATA\Programs\catcode\catcode.exe"
"%LOCALAPPDATA%\Programs\catcode\catcode.exe"
Likely cause: iex (Invoke-Expression) uses the caller's shell process.
After | iex, the shell exits because the installer runs exit.
Fix:
- Open a new terminal window (PowerShell, CMD, or Windows Terminal) after
installation so
PATHreloads. - Or use the scriptblock form to avoid the
iexexit issue:& ([scriptblock]::Create((irm https://raw.githubusercontent.com/catalystctl/catcode/refs/heads/master/install.ps1)))
- Launching
catcode: any of Windows Terminal, the PowerShell app, classic conhost PowerShell, or Command Prompt works once user PATH includes the install dir. Prefer Windows Terminal for full mouse/truecolor TUI support; legacy conhost may have weaker mouse/selection behavior. - Agent shell ≠ your interactive profile: the
bashtool defaults to PowerShell on unsandboxed Windows hosts even if your Windows Terminal profile is CMD or Git Bash. Align them withCATALYST_CODE_SHELL(e.g. full path tobash.exe, orcmd.exe) when you want the agent to match your interactive shell. - Web IDE terminal may open
cmd.exeviaCOMSPECwhile the agent still speaks PowerShell — that split is expected unless you override the shell.
Likely cause: The web frontend requires Node.js 22.13+ for runtime execution, or the MSI installer requires Windows Installer service.
Fix:
- Install Node.js 22.13+ first (the web bundle is prebuilt; only the runtime is needed).
- For the standalone
.exe, no runtime is needed — download thecatcode-<ver>-windows-x86_64.exefrom releases.
Symptom: install.sh / install-web.sh dies while "Resolving release" with:
error: could not resolve the latest release from
https://api.github.com/repos/catalystctl/catcode/releases/latest.
Likely causes:
- Host is missing
jqon older installer builds (the pipeline failed closed and looked like a private-repo / rate-limit error). - Unauthenticated GitHub API rate limit (60 req/hr per IP), common on shared WSL/CI networks.
- Network/DNS/TLS cannot reach
api.github.com.
Immediate workaround (always works): pin a known release tag:
curl -fsSL https://raw.githubusercontent.com/catalystctl/catcode/refs/heads/master/install-web.sh \
| bash -s -- --version 0a26423List tags/assets at releases.
Other fixes:
- Export a token to raise the API limit:
export GITHUB_TOKEN=ghp_...(orGH_TOKEN), then re-run the installer. - Retry later if rate-limited (HTTP 403/429).
- Current
install.shparsestag_namewithjqor puregrep/sed, sojqis no longer required for release resolution.
Likely causes: The core binary was not installed, was installed to a different prefix, or the install script's binary download failed.
Check:
- Run
catcode --version. If the TUI starts but the core doesn't, look for the core binary:which catcode-coreor check the install prefix. - On Linux:
/usr/local/bin/catcode-core - On macOS:
/usr/local/bin/catcode-coreor~/Library/Application Support/... - On Windows: in the install directory (same as
catcode.exe).
Fix:
- Re-run the installer. Use
--dry-runfirst to confirm download URLs. - If downloading from a mirror, check
--base-url. - Build from source if binaries are unavailable for your platform:
curl -fsSL https://raw.githubusercontent.com/catalystctl/catcode/refs/heads/master/install.sh | bash -s -- --build-from-source
Likely causes: Missing model provider configuration, corrupt session file, or incompatible system libraries.
Check:
- Run
catcode --debugand inspect~/.config/catalyst-code/debug.jsonl(HTTP bodies, tool args, protocol events, errors). - Look for a core crash log in the session directory.
- Try starting without a session file:
catcode --session /tmp/test-session.jsonl
- Check
~/.config/catalyst-code/config.jsonfor syntax errors.
Fix:
- Delete or rename the existing session file to rule out corruption.
- Reset the config:
mv ~/.config/catalyst-code/config.json ~/.config/catalyst-code/config.json.bak - Ensure at least one provider is configured (
/loginin the TUI).
Symptom: The web UI says "port already in use" or the service won't start.
Likely cause: Another process is already using the default port 49283.
Check:
lsof -i :49283Or on Windows:
netstat -ano | findstr :49283Fix:
- Start the service on a different port:
catcode --port 8080
- Or pass the port during install:
curl -fsSL ... | bash -s -- --port 8080 - Kill the existing process if it's a stale Catalyst Code instance.
Likely cause: The provider configuration is missing, incomplete, or the base URL is unreachable.
Check:
- Run
/loginto see configured providers and their status. - Check
~/.config/catalyst-code/config.jsonfor the provider entry. - Verify the
base_urlis reachable:curl -I <base_url>/models
Fix:
- Add a key-based provider:
catcode --add-provider my-provider --provider-kind openai --base-url https://api.example.com/v1
- Set the API key environment variable:
export MY_PROVIDER_API_KEY=sk-... - For Umans or OpenRouter, use the built-in login flow (
/login).
Symptom: The model responds with "401 Unauthorized" or "Invalid API key" immediately after the first request.
Likely cause: The API key is wrong, expired, or the environment variable is not set.
Check:
- Verify the env var name matches the provider's
api_key_envin config.json.echo $YOUR_PROVIDER_API_KEY
- Check the provider config:
cat ~/.config/catalyst-code/config.json | grep -A 10 '"providers"'
Fix:
- Set the correct env var:
export YOUR_PROVIDER_API_KEY=<actual-key> - If the key was set inline in the config (not recommended), move it to an env var.
- Restart the TUI after setting the env var (the config is read at startup).
Symptom: OpenRouter returns "User not found" with a 401 status.
Likely cause: Transient propagation delay after creating a new API key or account. OpenRouter's key validation can lag by several seconds.
Check:
- Wait 10–30 seconds and retry.
- Verify the key is valid at https://openrouter.ai/keys.
Fix:
- Retry the request. The error is almost always transient.
- If it persists beyond 60 seconds, generate a new API key at OpenRouter.
- The provider module has retry/backoff that handles this automatically in most cases.
Symptom: The model returns "429 Too Many Requests" or provider rate-limit errors after a burst of requests.
Check:
- Run
/usageto see provider plan and rate-limit windows. - Check the provider's rate-limit headers in verbose mode.
Fix:
- Wait for the rate-limit window to reset. The provider module has an automatic cooldown mechanism (default 30s minimum for 429s).
- Upgrade your provider plan for higher rate limits.
- Reduce
parallel_concurrencyin subagent configuration to avoid burst requests.
Symptom: The core cannot reach the model provider's API endpoint.
Likely cause: Network issues, incorrect base_url, or a local model server
that is not running.
Check:
curl -I <base_url>— verify the endpoint is reachable.- For local models (Ollama, LM Studio, vLLM), confirm the server is running
and listening on the expected port:
curl http://localhost:11434/api/tags # Ollama - Check for network proxies — the core uses
reqwestwithsystem-proxysoHTTP_PROXY/HTTPS_PROXY/ALL_PROXY/NO_PROXY(and Windows/macOS system proxy settings) are honored. A broken proxy (common on WSL when Windows injects a corporate proxy that is unreachable from the Linux side) makes every provider request fail with connect/tunnel errors. - On Linux/WSL, TLS uses rustls with both Mozilla webpki roots and the
system CA store (
/etc/ssl/certs). Corporate MITM proxies need their CA in the system trust store (or disable the broken proxy).
Fix:
- Start your local model server if it's not running.
- Correct the
base_urlin the provider configuration. - Check firewall rules — local model servers often bind to
127.0.0.1. - On WSL:
env | grep -i proxy. If a Windows-side proxy is set but dead from Linux,unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy(or pointNO_PROXYat your provider hosts) and restart catcode. - Prefer
127.0.0.1overlocalhostfor local servers (IPv6::1misses when the server binds IPv4-only).
Symptom: On Linux/WSL (or multi-provider setups) you type a prompt and
nothing hits the provider — no provider_request lines in
~/.config/catalyst-code/debug.jsonl, or the TUI only says
"not authenticated — run /login first" even though other providers are logged
in.
Likely causes:
- Active-provider-only auth gate (fixed): the TUI used to block all
sends when the active provider had no key, even if models from other
logged-in providers were selected. Stale
settings.jsonactive_provider(e.g.codexafter logout) or expired OAuth on the active provider triggered this. The core now emitsanyLoggedInonready, and the TUI/web allow sends when any configured provider is logged in (models still route to their owning provider). - Core never reached
ready: the TUI only sendsinitafter spawn; withoutreadywithin 30s the startup watchdog fails the core. Check the debug log andCATCODE_CORE. - Dead proxy / TLS: see "Connection refused" above.
Check:
# Did any HTTP leave the core?
tail -n 50 ~/.config/catalyst-code/debug.jsonl | grep provider_request
# Active provider vs configured providers
python3 -c 'import json; c=json.load(open("/home/$USER/.config/catalyst-code/config.json")); s=json.load(open("/home/$USER/.config/catalyst-code/settings.json")); print("config", c.get("activeProvider"), [p["name"] for p in c.get("providers",[])]); print("settings", s.get("active_provider"), s.get("model"))'(Replace $USER / paths as needed.)
Fix:
/loginthe provider you actually want, or/logouta stale active one and switch with the provider picker soactive_providermatches a keyed entry.- Ensure the selected model is owned by a logged-in provider (
/models). - Rebuild/reinstall after the multi-provider auth + HTTP client fix so
anyLoggedIn, native CA roots,http2, andsystem-proxyare present.
Symptom: The model picker shows the provider but no models are listed.
Likely cause: The provider's /models endpoint returned an empty or
unexpected response format.
Check:
curl <base_url>/modelsto see the raw response.- Some providers require authentication to list models — ensure the API key is set.
Fix:
- Verify the provider's discovery endpoint.
- For non-standard providers, a code branch in
core/src/provider.rsmay be needed (see theadd-key-providerskill).
Symptom: The browser opens for OAuth login but the TUI doesn't detect completion, or the provider stays "not logged in."
Likely cause: Port forwarding, firewall, or browser security blocking the loopback redirect.
Check:
- Ensure the OAuth callback port is not blocked by a firewall.
- Check browser developer tools for mixed-content or CORS warnings.
- Verify
localhostresolves correctly (/etc/hosts).
Fix:
- Use the manual code option in the OAuth flow (copy-paste the code instead of relying on the callback).
- Check network proxies that might interfere with localhost routing.
- Ensure no other service is using the OAuth callback port.
Symptom: A tool call (read_file, write_file, edit, glob, etc.) fails with a path confinement error.
Cause: Catalyst Code enforces workspace confinement — all file paths must
resolve to within the workspace directory. Absolute paths, .., and symlink
escapes are rejected.
Check:
- Is the path relative? The tool requires workspace-relative paths.
- Does the path resolve to a location outside the workspace?
- Are there symlinks that point outside the workspace?
Fix:
- Use paths relative to the workspace root.
- Do not use absolute paths or
..traversal. - Access files outside the workspace via
bashcommands (with approval gate).
Symptom: bash / git / diagnostics tool calls fail with a sandbox-related
error, or enabling the sandbox shows a setup-required message.
Likely cause: Microsandbox preflight found the environment is not ready
(missing virtualization, /dev/kvm permissions, Windows Hypervisor Platform
off, runtime/image not downloaded, or an unsupported platform like Intel macOS).
Check:
- Run the preflight from the TUI/web
/sandboxsettings or:The report lists each check's status and the exact remediation command./sandbox status /sandbox recheck - Linux quick check:
test -r /dev/kvm && test -w /dev/kvm && echo "KVM is ready"
- Windows:
Get-WindowsOptionalFeature -Online -FeatureName HypervisorPlatform
Fix:
- Follow the platform-specific setup in the Sandbox Guide
(enable VT-x/AMD-V in BIOS,
sudo usermod -aG kvm "$USER"+ relogin on Linux,Enable-WindowsOptionalFeature ... HypervisorPlatformon Windows). - Run
/sandbox setupto prepare the user-space runtime + image assets (no admin install), then/sandbox recheck. - If the platform cannot run Microsandbox (e.g. Intel macOS), explicitly disable
sandboxing:
or at runtime:
catcode --sandbox none
/sandbox disable
CatCode fails closed: it never silently runs commands on the host when the sandbox is requested but unavailable.
Symptom: A tool call (bash, fetch, search) does not complete.
Likely cause: The tool's operation is blocked (network, user input in bash, infinite loop) or exceeds the timeout.
Fix:
- Use
/abortto cancel the in-flight turn. - Long-running operations should be split into smaller tool calls.
- Check network connectivity for
fetchand search tools.
Symptom: A plugin in .catalyst-code/plugins/ does not appear or its
hooks do not fire.
Check:
- Verify the plugin directory structure:
.catalyst-code/plugins/<plugin-name>/ plugin.json - Check plugin.json for syntax errors:
cat .catalyst-code/plugins/<name>/plugin.json - Look for load errors in the core's debug log.
Fix:
- Ensure
plugin.jsonfollows the plugin schema exactly (see Plugin Authoring Guide). - Restart the TUI so the core re-scans the plugins directory.
- Check the plugin's required dependencies (e.g. a runtime for hook scripts).
Symptom: A plugin hook should fire but nothing happens, or the turn completes without the hook's side effects.
Check:
- The plugin system runs hooks fail-open — a failing hook does not block the turn. Check the debug log for hook errors.
- Verify the hook name is correct (
session_start,session_stop,pre_compact,pre_turn,pre_<tool>,post_<tool>).
Fix:
- Add error logging to the hook script to capture failure details.
- Test the hook script independently:
bash .catalyst-code/plugins/<name>/hook-script.sh
Symptom: A plugin cannot access files or resources it needs.
Cause: Plugins run with the same permissions as the core process. If the core is sandboxed, the plugin is also sandboxed.
Fix:
- Set appropriate file permissions for files the plugin needs to read/write.
- If the plugin needs network access, ensure the core's network policy allows it.
- Plugins that write to the workspace inherit workspace confinement rules.
Symptom: On startup or when loading a session, the core emits an error:
session file is version X, newer than supported (1); not loaded to avoid corrupting it.
Cause: The session file was created by a newer version of Catalyst Code that uses an incompatible message format.
Check:
- Check the file's first line:
head -1 <session-file>.jsonl
- Compare your binary version:
catcode-core --version
Fix:
- Upgrade Catalyst Code to the version that created the session.
- If upgrade is not possible, delete the session file to start fresh (the old file can be archived for later migration).
- A migration tool is not yet available — the
_session_versionmechanism is designed to prevent silent data loss until one exists.
Symptom: After a crash (power loss, kill -9), the session loads but the last turn's messages are missing.
Cause: This is by design — the crash-safety model guarantees at most
one lost in-flight turn. Messages are flushed to the kernel during the turn
but are only fsync'd at turn end. A crash between turn start and turn-end
fsync loses the in-progress messages.
Check:
- The session file ends at the last successfully completed turn. Earlier messages are intact because the append + atomic rewrite pattern protects them.
- Only the (incomplete) turn that was in flight at crash time is missing.
Fix:
- Use
/undoafter restart if the filesystem was also affected (restores from the latest auto-checkpoint). - No data recovery is possible for the lost turn — it was never committed to disk.
Symptom: Cannot delete or overwrite a session file. The TUI shows "session is active in another process."
Cause: A .lock sidecar file indicates another Catalyst Code instance is
using this session.
Check:
- Look for
.lockfiles beside the session:ls -la <session-file>.lock
- Check the PID in the lock file:
cat <session-file>.lock
Fix:
- Close the other instance, or kill the stale process if it crashed without
cleaning up:
kill <pid>
- If the process is already dead, remove the
.lockfile manually. - The lock prevents two instances from corrupting the same session file; removing it when no other process is active is safe.
Check:
- Session deletion removes the
.jsonl,.meta.json,.stats, and.meta.lockfiles. - No built-in trash/recycle bin exists.
Fix:
- If you have filesystem snapshots or backup, restore from there.
- Sessions are stored at
~/.config/catalyst-code/sessions/<hash>/.
See Port conflict above.
Likely cause: The web service is not running or is bound to a different host/port.
Check:
- Is the service running? Look for
catcodeorcatcode-corein process list. - What port was it configured with? Default:
49283. - Is it listening on
0.0.0.0or127.0.0.1?
Fix:
- Start the service:
catcode(TUI) automatically starts the web backend. - If running headless:
catcode-core serve --port 49283 - If the service is bound to
127.0.0.1, access it only from the same machine.
Symptom: The web UI loads but the model response never arrives. Browser
dev console shows "Mixed Content: The page was loaded over HTTPS but attempted
to connect to an insecure WebSocket endpoint ws://..."
Cause: When the panel is served over HTTPS (e.g. via a reverse proxy like
Caddy/nginx), the WebSocket connection to the core must also be wss://
instead of ws://.
Fix:
- Serve the frontend over HTTP on the local machine (the default) — there's no sensitive data in transit over localhost.
- If you must use HTTPS, configure a WebSocket proxy that upgrades the connection to WSS.
- Or use the TUI instead of the web frontend — the TUI connects directly over stdio, avoiding the issue entirely.
Symptom: The web service fails to start because Node.js is missing or older than 22.13.
Cause: The prebuilt web bundle needs a JavaScript runtime to serve files (statically, with the API proxy). The runtime is not bundled with the installer.
Check:
node --version- The preset install path for the web server binary.
Fix:
- Install Node.js 22.13 or newer. Bun cannot run this server because
authentication uses Node's built-in
node:sqlitemodule. - The installer validates the Node version during setup.
- Fall back to the TUI-only install (
install.shwithout--with-web).
Symptom: Running catcode --update exits silently or says "up to date"
but you know a newer release exists.
Check:
- Run
catcode --versionto see the current version. - Check the releases page for the latest version.
- Run the installer with
--updateflag:curl -fsSL https://raw.githubusercontent.com/catalystctl/catcode/refs/heads/master/install.sh | bash -s -- --update
Fix:
- The
--updateflag re-downloads and reinstalls the CLI, core, and web bundle (if installed), then restarts the service. - If the service is managed by systemd/launchd/NSSM, the updater restarts it automatically.
- On Windows, use
install.ps1 -Update.
Symptom: The installer downloads a release but fails checksum verification.
Cause: Corrupted download or man-in-the-middle.
Fix:
- Retry the update — the error is usually a transient network issue.
- Specify a specific version to pin downloads:
... | bash -s -- --version 0.2.0 - Check the release checksums against the published values on GitHub.
| Command | What it shows |
|---|---|
/stats |
Cumulative tokens, turns, cache ratio, context size |
/usage |
Provider plan and rate-limit windows |
/models |
Available models across all providers |
/sessions |
Session picker with metadata |
/memory |
Memory catalog |
/compact |
Manual context compaction |
/set |
Current runtime configuration |
catcode --version |
Binary version |
For deeper diagnostics, check the debug log at ~/.config/catalyst-code/logs/
or run with RUST_LOG=debug.
- Open a GitHub issue
- Check existing issues for similar symptoms.
- Include the output of
/stats,/sessions, and the core debug log. - For crash bugs, include the core's stderr output and the session file header
(first line of the active
.jsonl).