Envoy Troubleshooting¶
Server Won't Start¶
Symptoms: Toggling Envoy Enable does nothing, no port number appears in the toolbar, or errors in the Textport.
- Check the Textport (Alt+T) — Embody logs all startup messages there. Look for lines starting with
[Envoy]. - Dependency install in progress: On first enable (or after a version upgrade), Envoy builds its virtual environment and installs
mcp,uvicorn, and other packages. This runs in a background thread — the status readsInstalling deps... (one-time)and the port appears only when it finishes. A fresh install can take a minute or two; wait for it rather than re-toggling. If it failed (e.g., no internet, Python version mismatch), the status showsError: Python environment not ready. Check for pip errors in the Textport and try installing manually: On Windows, also add"pywin32>=306". - Port already in use: If another process is using port 9870 (the default), the server will fail to bind. Change the Envoy Port parameter on the Embody COMP to a different port (e.g., 9871).
- TD version too old: Envoy requires TouchDesigner 2025.32820 or later.
Restart Loop: "Unable to configure formatter 'default'"¶
Symptoms: Envoy never comes up; the Textport repeats a traceback ending in
AttributeError: 'Logger' object has no attribute 'isatty'
ValueError: Unable to configure formatter 'default'
every ~10–25 seconds, with noticeable freezes or frame drops as the watchdog keeps restarting the server.
Cause: TouchDesigner replaces sys.stdout with a Textport catcher object, and some TD builds (confirmed on 2025.32460 on Windows) ship one without an isatty() method. uvicorn's default log formatter probes sys.stdout.isatty() during server construction, so startup dies before the socket ever binds — and Envoy's liveness watchdog restarts the dead server indefinitely.
Fix:
- Update Embody to v6.0.116 or later — Envoy now passes
use_colors=Falseto uvicorn, which skips theisatty()probe entirely. - Or update TouchDesigner to 2025.32820 or later (the documented minimum) — those builds ship a stdout catcher that implements
isatty().
Do not patch .venv/.../uvicorn/logging.py by hand — the edit is lost whenever the virtual environment is rebuilt (TD upgrades, dependency floor bumps, venv repair).
Claude Code Can't Connect¶
Symptoms: Claude Code says "MCP server not found" or tool calls time out.
- Verify Envoy is running: Check that the Embody toolbar shows a port number next to the Envoy toggle. If not, see "Server Won't Start" above.
- Check
.mcp.json: Look for.mcp.jsonat your AI Project Root — the git repo root by default, or the.toe's folder / a custom path if you've changed the AI Project Root parameter. It should contain a server entry forenvoywith the correct port. If it's missing:- Confirm the AI Project Root parameter points where you expect (a non-git project still gets
.mcp.jsonwritten to the project folder) - Re-enable Envoy (toggle off, then on) to regenerate it
- Or create it manually — see Manual Configuration
- Confirm the AI Project Root parameter points where you expect (a non-git project still gets
- Restart Claude Code: After Envoy generates
.mcp.json, you need to start a new Claude Code session for it to pick up the config. Runclaudeagain in your project directory. - Port mismatch: Ensure the port in
.mcp.jsonmatches the Envoy Port parameter in TD. If you changed the port,.mcp.jsonshould update automatically — but check it. - Firewall or proxy: Envoy binds to
127.0.0.1(localhost only). If you're running Claude Code on the same machine, firewalls shouldn't be an issue. If using a remote setup, Envoy does not support remote connections.
Git Initialization Failed¶
Symptoms: Envoy starts and MCP config is generated, but .gitignore and .gitattributes are missing.
Since v5.0.264, Envoy generates MCP and AI client config files (.mcp.json, CLAUDE.md, .claude/, etc.) regardless of whether a git repo exists — they are written to the project folder as a fallback. Only .gitignore and .gitattributes require a git repo.
- No git repo: If you later create one, run
op.Embody.InitGit()from the textport to generate git config and update MCP paths to point to the git root. - Git init error: If Envoy attempted to initialize git and failed, a dialog will explain the error. Common causes:
gitnot on your system PATH- Permissions issue in the project directory
- TouchDesigner's embedded Python environment conflicting with git (Envoy strips known problematic env vars, but edge cases exist)
- Verify manually: Open a terminal in your project directory and run
git rev-parse --is-inside-work-tree. If this returnstrue, git is working and you can runop.Embody.InitGit()to generate the missing files.
Curl Fallback Not Working¶
If Claude Code can't use MCP transport, it may try to reach Envoy via curl. Verify the server is reachable:
You should get a response (even if it's an error about missing JSON body). If you get "connection refused," the server isn't running or is on a different port.
MCP Disconnects Mid-Session¶
Symptoms: Claude Code stops being able to call Envoy tools mid-conversation — tool calls fail with connection errors or timeouts, even though TD is still running and Envoy shows as enabled.
This can happen if TouchDesigner restarts, the Envoy server cycles, or the bridge process exits unexpectedly.
Claude Code CLI¶
Restart the session by exiting (Ctrl+C or /exit) and running claude again in your project directory. The bridge will reconnect to Envoy automatically.
Claude Code VS Code Extension¶
- Close the conversation tab in the editor.
- Open the Claude Code sidebar (click the Claude icon in the Activity Bar on the left).
- Click the conversation to reopen it — your full message history is restored.
Reopening the conversation re-initializes the MCP connection. The message history is preserved, so you can continue where you left off.
Tip
If you want a completely fresh start instead, type /clear in the conversation. This wipes the message history but keeps the tab open with a new MCP connection.
Multiple Instances¶
Wrong instance responding¶
Symptoms: MCP tool calls affect a different TD project than expected, or execute_python returns unexpected project.name.
- Check which instance is active: Call
switch_instancewith no arguments — it lists all registered instances and marks which one the bridge is targeting. - Switch to the correct one: Call
switch_instancewith the instance name (.toefilename without the extension). - Stale entries: If an instance shows as "reachable" but you've already closed it, the registry entry is stale. Restarting Envoy in the running instance will clean it up.
Same-file instance naming¶
Symptoms: You opened the same .toe file in two TD instances and want predictable names for switch_instance.
Envoy auto-suffixes duplicate keys (MyProject, MyProject-2, etc.), so both instances are addressable.
Port exhaustion¶
Symptoms: Envoy fails to start with a message about no available ports.
Envoy scans 10 ports (default: 9870–9879). If all are occupied, it can't start. Close unused TD instances or change the Envoy Port parameter to a different base (e.g., 9880).
Broken Virtual Environment¶
Symptoms: Bridge process doesn't start at all, or starts and immediately exits. dev/logs/envoy-bridge.log is empty or shows a Python traceback about a missing interpreter. .mcp.json command points to a .venv/ Python that doesn't work.
Cause: The .venv was created from a TouchDesigner Python installation that has since been upgraded or removed. The home key in .venv/pyvenv.cfg points to a path that no longer exists (common on Windows with versioned TD directories like TouchDesigner.2025.32460/).
Fix:
- Delete the broken venv:
rm -rf <project_dir>/.venv - Toggle Envoy off and on in TouchDesigner (or restart TD) — Envoy will recreate the venv automatically
- Reopen your Claude Code session so the bridge reconnects with the new venv Python
Note
Envoy validates the venv Python on startup. If the venv interpreter fails to execute, Envoy falls back to the system Python and logs a warning to the Textport. Check for "failed to execute" warnings after TD upgrades.
Log Files¶
Embody writes detailed logs to the log folder in your project directory (default logs/, set by the Log Folder parameter). Check the most recent <project>_YYMMDD.log file for the full picture — the Textport ring buffer only holds 200 entries.