Troubleshooting
This guide covers common issues encountered when running AgentVisor™, organized by symptom for quick diagnosis.
Sandbox Startup Failures
gVisor not available
Symptom: Error message runsc not found or gvisor sandbox unavailable.
Cause: The gVisor runtime (runsc) is not installed or not in PATH. gVisor is only available on Linux.
Fix:
- Verify you're on Linux — gVisor doesn't support macOS or Windows
- Install gVisor: https://gvisor.dev/docs/user_guide/install/
- Ensure
runscis in PATH or configureguest.runsc_pathin your config:guest:runsc_path: /usr/local/bin/runsc
Workaround: Use --sandbox=docker on macOS/Windows, or --sandbox=none for local development.
gVisor rootless preflight failed
Symptom: Error at startup: gVisor rootless mode is enabled but cannot create user namespaces on this host.
Cause: The host is blocking creation of unprivileged user namespaces. gVisor rootless mode requires unshare(CLONE_NEWUSER) to succeed. Three things can block it:
- Kernel sysctl
kernel.unprivileged_userns_clone=0(Debian, older Ubuntu) - Container seccomp profile blocking the syscall (Kubernetes and Docker default profiles)
- AppArmor restricting unprivileged user namespaces (Ubuntu 24.04+, GKE, AKS, Azure Linux 3)
Fix — Kubernetes:
securityContext:
seccompProfile:
type: Unconfined
appArmorProfile: # Kubernetes 1.30+
type: Unconfined
On clusters older than 1.30, use the legacy annotation on the Pod:
metadata:
annotations:
container.apparmor.security.beta.kubernetes.io/<container-name>: unconfined
Fix — Docker:
docker run \
--security-opt seccomp=unconfined \
--security-opt apparmor=unconfined \
...
Fix — Host sysctl:
sudo sysctl -w kernel.unprivileged_userns_clone=1
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
Cloud-specific notes:
- GKE: Standard node pools on COS+containerd require both
seccompProfileandappArmorProfileset toUnconfined. - AKS: Mariner/Azure Linux 3 nodes enforce AppArmor by default; set
appArmorProfile: Unconfinedrather than falling back toprivileged: true. - EKS: Bottlerocket and Amazon Linux 2023 generally only need seccomp unconfined, but check
cat /proc/sys/kernel/apparmor_restrict_unprivileged_usernson the node.
Diagnose on the node:
# Check userns sysctl
cat /proc/sys/kernel/unprivileged_userns_clone # should be 1 (or file absent)
cat /proc/sys/user/max_user_namespaces # should be > 0
# Check AppArmor restriction (Ubuntu 24.04+)
cat /proc/sys/kernel/apparmor_restrict_unprivileged_userns # should be 0 (or file absent)
Workaround: Switch to privileged mode by setting AGENTVISOR_GUEST_ROOTLESS=false and securityContext.privileged: true. This trades the least-privilege posture for broader compatibility.
Docker socket permission denied
Symptom: Error permission denied while trying to connect to the Docker daemon socket.
Cause: The current user lacks permission to access /var/run/docker.sock.
Fix:
- Add your user to the
dockergroup:sudo usermod -aG docker $USER - Log out and back in (or run
newgrp docker) - Verify with
docker ps
Alternative: Run with sudo (not recommended for development).
Guest health check timeout
Symptom: Error guest health check failed: context deadline exceeded or startup timeout.
Cause: The guest runtime didn't become ready within the configured timeout. Common reasons:
- Slow container image pull
- Resource constraints (CPU/memory limits too low)
- Missing dependencies in the guest image
- Agent crashes during initialization
Fix:
- Increase the startup timeout:
guest:startup_timeout: 60s # Default: 30s
- Check if the base image needs to be pulled:
docker pull ghcr.io/manetu/agentvisor/agentvisor-guest:latest-python
- Review agent logs for initialization errors:
agentvisor serve . --sandbox=none # Test without sandbox first
- Increase resource limits if the agent is memory-intensive:
guest:memory_limit: 1073741824 # 1GB
Policy Evaluation Errors
AUTHZ_TYPE not set
Symptom: Error authorization configuration required: set authz.type (available: [allowall embedded http]).
Cause: The authorization provider type is not configured. This is a required setting.
Fix: Configure an authorization provider:
authz:
type: embedded # Or: http, allowall
embedded:
policy_domain_files: "/path/to/policy.yml"
Or via environment variable:
export AGENTVISOR_AUTHZ_TYPE=embedded
export AGENTVISOR_AUTHZ_EMBEDDED_POLICY_DOMAIN_FILES="/path/to/policy.yml"
For development without policies, use allowall (never in production):
export AGENTVISOR_AUTHZ_TYPE=allowall
Policy file not found
Symptom: Error failed to load policy domain file: open /path/to/policy.yml: no such file or directory.
Cause: The path in policy_domain_files doesn't exist or isn't readable.
Fix:
- Verify the file exists:
ls -la /path/to/policy.yml
- Use absolute paths — relative paths resolve from the working directory
- For multiple files, separate with commas:
authz:embedded:policy_domain_files: "/etc/agentvisor/base.yml,/etc/agentvisor/custom.yml"
Tip: Every scaffolded project (agentvisor template create) ships a starter policy at
policies/domain.yml:
export AGENTVISOR_AUTHZ_EMBEDDED_POLICY_DOMAIN_FILES="./policies/domain.yml"
Allow-all warning in production
Symptom: The host runtime logs this warning at startup:
SECURITY: allowall authorization provider is active - ALL requests are permitted without policy evaluation. NEVER use in production.
Cause: The allowall authorization provider is configured, which disables all security controls.
Detect it: Grep logs for the stable fragment (not the full sentence, which may be reworded):
grep "allowall authorization provider is active" /path/to/agentvisor.log
A deployment is safe from this specific bypass only when this grep finds nothing.
Fix: Never use allowall in production. Configure a real authorization provider:
authz:
type: embedded
embedded:
policy_domain_files: "/etc/agentvisor/policies/production.yml"
Authorization denied unexpectedly
Symptom: Error authorization denied for action X on resource Y when the action should be allowed.
Cause: The policy doesn't grant the required permission, or the principal doesn't match what the policy expects.
Debug steps:
-
Enable pretty-printed access logs for debugging:
authz:embedded:access_log_output: stdout # or logger, stderr, /path/to/fileaccess_log_format: pretty # indented JSON (use json for compact)Or via environment variable:
AGENTVISOR_AUTHZ_EMBEDDED_ACCESS_LOG_OUTPUT=stdout AGENTVISOR_AUTHZ_EMBEDDED_ACCESS_LOG_FORMAT=prettynoteIn
agentvisor execmode the default isoutput: loggerto keep the terminal clean. Use--verboseor--log-fileto see access log entries in that mode. -
Check the logs to see the exact PORC (Principal, Operation, Resource, Context) being evaluated
-
Verify the principal in the request matches what your policy expects
-
Check MRN format — common resources:
- HTTP:
mrn:agentvisor:http:<host>/<path> - Tools:
mrn:agentvisor:tool:<name> - MCP:
mrn:agentvisor:mcp:<server_name>/<tool_name> - A2A:
mrn:agentvisor:a2a:<agent_name>(agent) ormrn:agentvisor:a2a:<agent_name>/task/<task_id>(task)
- HTTP:
Temporal Connectivity
Connection refused
Symptom: Error connection refused or failed to connect to Temporal at localhost:7233.
Cause: Temporal server isn't running or isn't accessible at the configured address.
Fix:
- Start Temporal for local development:
temporal server start-dev
- Or start via Docker Compose:
docker compose up -d temporal
- Verify connectivity:
temporal workflow list --namespace default
- If using Temporal Cloud, verify the target address includes port 7233:
temporal:target: my-namespace.account-id.tmprl.cloud:7233
Namespace not found
Symptom: Error namespace not found: my-namespace.
Cause: The configured namespace doesn't exist in Temporal.
Fix:
- For local Temporal, create the namespace:
temporal operator namespace create my-namespace
- For Temporal Cloud, the namespace format is
namespace.account-id:temporal:namespace: my-namespace.abc123 - Verify available namespaces:
temporal operator namespace list
Temporal Cloud authentication failures
Symptom: Error authentication failed or permission denied when connecting to Temporal Cloud.
Cause: API key or mTLS certificates are missing, expired, or misconfigured.
For API key authentication:
- Verify the API key is set (never put it in config files):
export AGENTVISOR_TEMPORAL_AUTH_API_KEY="your-api-key"
- Ensure the auth type is configured:
temporal:auth:type: api_key
- Check that the API key hasn't expired in Temporal Cloud UI
For mTLS authentication:
- Verify certificate files exist and are readable:
ls -la /path/to/client.crt /path/to/client.key
- Check certificate expiry:
openssl x509 -enddate -noout -in /path/to/client.crt
- Ensure the namespace matches the certificate:
temporal:target: my-namespace.account-id.tmprl.cloud:7233namespace: my-namespace.account-idauth:type: mtlsmtls:cert_file: "/path/to/client.crt"key_file: "/path/to/client.key"
Proxy Credential Substitution
Symbolic token not substituted
Symptom: Upstream API returns 401 Unauthorized or invalid API key, and logs show the symbolic token (e.g., mav-tok-...) being sent instead of the real credential.
Cause: The credential resolver isn't matching the request. Common reasons:
destinationsregex doesn't match the target host- The request uses
http://instead ofhttps://(credentials require https by default — setallow_insecure: trueon the rule to opt in to plaintext) - The request targets a non-standard port (only the scheme's standard port matches: 443 for https, 80 for http)
- The credential isn't configured for the header being used
- Environment variable with real credential isn't set
Fix:
- Check that the destination regex matches the target host:
proxy:credentials:- name: anthropic-keydestinations:- "api\\.anthropic\\.com" # Note: dots must be escaped
- Verify the environment variable with the real API key is set:
echo $ANTHROPIC_API_KEY # Should show the real key, not mav-tok-...
- Check logs for credential resolution messages
Destination regex not matching
Symptom: Credential substitution works for some hosts but not others.
Cause: The regex pattern doesn't match the actual hostname. Patterns are auto-anchored (implicitly wrapped with ^ and $).
Common mistakes:
# WRONG: Missing escape for dots
destinations:
- "api.anthropic.com" # Matches "apiXanthropicYcom"
# CORRECT: Escaped dots
destinations:
- "api\\.anthropic\\.com" # Matches only "api.anthropic.com"
# WRONG: Partial match expected
destinations:
- "anthropic" # Won't match "api.anthropic.com"
# CORRECT: Use .* for partial matching
destinations:
- ".*\\.anthropic\\.com" # Matches "api.anthropic.com", "upload.anthropic.com"
Debug: Enable debug logging and watch for credential resolution messages:
AGENTVISOR_LOG_LEVEL=debug agentvisor serve .
Missing destinations field
Symptom: Error destinations is required for proxy credential or credential applies to all hosts unexpectedly.
Cause: The destinations field is required to prevent credentials from leaking to unintended hosts.
Fix: Always specify which hosts should receive the credential:
proxy:
credentials:
- name: my-api-key
guest_env_var: MY_API_KEY
destinations:
- "api\\.myservice\\.com"
- "api\\.myservice\\.io"
resolver:
type: bearer_token
source: env
env_var: MY_API_KEY
Guest TLS Errors
SSL certificate errors in agent
Symptom: Agent code fails with SSL: CERTIFICATE_VERIFY_FAILED or unable to get local issuer certificate.
Cause: The agent isn't using the ephemeral CA certificate that AgentVisor generates for TLS interception.
Fix:
- Ensure
SSL_CERT_FILEis set in the agent environment (AgentVisor sets this automatically) - If using custom HTTP clients, configure them to use the system CA bundle:
import httpx# Uses SSL_CERT_FILE automaticallyclient = httpx.Client()
- For requests library:
import osimport requests# requests uses SSL_CERT_FILE when REQUESTS_CA_BUNDLE isn't setresponse = requests.get("https://api.example.com")
For unsandboxed mode (--sandbox=none): The CA certificate isn't injected automatically. Either:
- Use
--sandbox=dockerfor testing TLS behavior - Or disable TLS verification for local debugging only (never in production)
CA certificate not injected
Symptom: SSL_CERT_FILE environment variable is empty or points to a non-existent file.
Cause: Running in --sandbox=none mode, which bypasses the guest runtime and CA injection.
Fix: This is expected behavior for --sandbox=none. The ephemeral CA is only needed when running through the TLS-intercepting proxy, which requires a sandbox.
Workaround for local testing:
- Use
--sandbox=dockerto test with full TLS interception - Or configure your agent to skip TLS verification in development only
Certificate expiry warnings
Symptom: Warning certificate expires soon or TLS errors after running for extended periods.
Cause: Per-host certificates have a default validity of 1 hour. For long-running sandboxes, certificates may expire.
Fix: These are environment-variable-only knobs, not YAML config keys. Increase certificate validity for long-running development sessions:
export AGENTVISOR_GUEST_CERT_VALIDITY=24h # Default: 1h
The ephemeral CA has a default validity of 30 days:
export AGENTVISOR_GUEST_CA_VALIDITY=90d # Default: 30d
MCP Gateway Issues
Connection pool exhausted
Symptom: Error connection pool exhausted or too many connections for MCP servers.
Cause: The number of concurrent principal-bound MCP connections exceeds the pool limit.
Fix: Increase the pool size:
mcp:
pool:
max_size: 200 # Default: 100
Alternative: Review if you need principal-bound credentials. Static credentials (bearer_token, api_key) share a single connection and don't consume pool slots.
MCP idle timeout
Symptom: MCP tool calls fail intermittently with connection errors after periods of inactivity.
Cause: Idle connections are being closed but the agent expects them to remain open.
Fix: Adjust the idle timeout based on your usage pattern:
mcp:
pool:
idle_timeout: 15m # Default: 5m
Note: Longer timeouts consume more resources. If agents use MCP servers sporadically, shorter timeouts with automatic reconnection may be more efficient.
MCP credential resolution failures
Symptom: Error failed to resolve credentials for MCP server or token exchange failed.
For bearer_token resolver:
- Verify the environment variable is set:
echo $GITHUB_TOKEN
- Check the configuration matches:
mcp:servers:- name: githubcredentials:type: bearer_tokensource: envenv_var: GITHUB_TOKEN # Must match actual env var
For token_exchange resolver:
- Verify the exchange URL is accessible
- Check that the principal JWT is valid and not expired
- Ensure the audience matches what the token exchange server expects:
credentials:type: token_exchangeexchange_url: "https://auth.example.com/token"audience: "github-mcp" # Must match server's expected audience
A2A Gateway Issues
A2A connection pool exhausted
Symptom: Error connection pool exhausted or too many connections for A2A agents.
Cause: The number of concurrent principal-bound A2A connections exceeds the pool limit.
Fix: Increase the pool size:
a2a_gateway:
pool:
max_size: 200 # Default: 100
Alternative: Review if you need principal-bound credentials. Static credentials (bearer_token, api_key, no auth) share a single connection per agent and don't consume pool slots.
A2A idle timeout
Symptom: A2A calls fail intermittently with connection errors after periods of inactivity.
Cause: Idle connections are being closed but the agent expects them to remain open.
Fix: Adjust the idle timeout based on your usage pattern:
a2a_gateway:
pool:
idle_timeout: 15m # Default: 5m
Note: Longer timeouts consume more resources. If agents call a given A2A agent sporadically, shorter timeouts with automatic reconnection may be more efficient.
A2A credential resolution failures
Symptom: Error failed to resolve credentials for A2A agent or token exchange failed.
For bearer_token resolver:
- Verify the environment variable is set:
echo $RESEARCH_AGENT_TOKEN
- Check the configuration matches:
a2a_gateway:agents:- name: research-agentcredentials:type: bearer_tokensource: envenv_var: RESEARCH_AGENT_TOKEN # Must match actual env var
For token_exchange resolver:
- Verify the exchange URL is accessible
- Check that the principal JWT is valid and not expired
- Ensure the audience matches what the token exchange server expects
Upstream JSON-RPC error codes
The A2A Gateway client maps a subset of A2A's implementation-defined JSON-RPC error
codes (internal/host/a2a/types) to Go sentinel errors; the rest surface as a raw
JSON-RPC error with the code and message the external agent supplied:
| Code | Meaning | Gateway client behavior |
|---|---|---|
-32001 | Task not found | Wrapped as ErrTaskNotFound |
-32002 | Unauthorized | Wrapped as ErrUnauthorized |
-32003 | Forbidden | Wrapped as ErrForbidden |
-32004 | Conflict | Not wrapped — raw JSON-RPC error |
-32005 | Service unavailable | Wrapped as ErrUnavailable |
-32006 | Operation timed out | Wrapped as ErrTimeout |
-32007 | Invalid task state | Wrapped as ErrInvalidState |
-32008 | Agent not found | Not wrapped — raw JSON-RPC error |
-32009 | Message rejected | Not wrapped — raw JSON-RPC error |
Standard JSON-RPC 2.0 codes (-32700 parse error, -32601 method not found, etc.) can
also surface. agentvisor a2a probe's tasks/list stage specifically treats
method-not-found as unsupported rather than a failure — an agent with no
task-listing support is still a reachable, working agent.
Only unauthorized and forbidden map to the auth_error classification used by
audit records, GET /ready, and probe output. Every other code above — including
operation timed out and service unavailable — falls into the generic
connection_error bucket, because classification pattern-matches on the error's text
rather than the JSON-RPC code itself ("operation timed out" does not contain the
substring "timeout"). If error_class reads connection_error, don't assume a
network-layer failure — check the verbatim message with
AGENTVISOR_LOG_LEVEL=info,a2a=debug,a2a.client=debug before drawing a conclusion.
Interpreting GET /ready
GET /ready reports MCP and A2A connectivity under the mcp and a2a keys, each a
ComponentStatus:
{
"status": "degraded",
"warnings": ["mcp_servers_unavailable"],
"mcp": {
"configured": 3,
"connected": 2,
"failed": 1,
"principal_bound": 1,
"failed_endpoints": [
{"name": "github", "error": "auth_error", "phase": "startup", "since": "2026-08-10T18:00:00Z"}
]
}
}
failed_endpoints[]— one entry per server/agent with a currently failed recorded outcome.erroris the same coarse classification code (connection_refused,dns_error,tls_error,auth_error,timeout,credential_error,connection_error) used byagentvisor mcp probe/agentvisor a2a probe— never the raw error text, which stays host-side in the log. This array (and the failure detail inside it) is only returned to a caller MPE authorizes foragentvisor:system:ready-detailagainstmrn:agentvisor:system:ready; every other caller — including an unauthenticated one — sees the counts only, withfailed_endpointsomitted.phase—"startup"if the current failure streak began before the gateway manager finished starting,"runtime"if it began from a live call afterward. Aruntimefailure also raises the coarsemcp_servers_degraded_at_runtime/a2a_agents_degraded_at_runtimewarning, visible even to a caller not authorized to seefailed_endpoints.since— an RFC3339 UTC timestamp marking the start of the current consecutive failure streak, not the first failure ever observed. A successful call clears it; if the endpoint then fails again, that's a new streak with a newsince, not a resumption of the old one.- Observed, not probed — every count here comes from real traffic, never a
background health check. A static endpoint is marked
connected/failedfrom its real connection attempt at startup. A principal-bound endpoint (principal_passthrough,token_exchange) that no principal has ever called has no recorded state at all — it counts towardprincipal_boundbut appears in neitherconnectednorfaileduntil some principal actually exercises it.GET /readynever proactively dials an endpoint on your behalf; useagentvisor mcp probe/agentvisor a2a probefor that. - TTL decay — a runtime-phase failure with no confirming traffic (a success or
another failure) for 5 minutes is dropped from
failed_endpointsentirely — reported as neither failed nor connected, since there's no longer positive evidence of either. Startup-phase failures never decay this way; they persist until a later successful call clears them. - The invariant —
configuredis not guaranteed to equalconnected + failed + principal_bound. An unused principal-bound endpoint is the gap: it's counted once, inprincipal_bound, but not yet inconnectedorfailed.
Schema Extraction Issues
schema_cli fails
Symptom: Error during agent startup: failed to extract schema or python3 -m agentvisor.schema_cli returned error.
Cause: The schema extraction script can't import or analyze your agent code. Common reasons:
- Missing dependencies
- Import errors in agent code
- Python version mismatch
- Timeout (default: 30s)
Fix:
- Test schema extraction manually (bare invocation prints help and exits 1 — pass
--export):cd your-agentpython3 -m agentvisor.schema_cli --export . - Fix any import errors in your agent code
- Ensure all dependencies are installed:
pip install -r requirements.txt
- Check for circular imports or heavy initialization code that runs at import time
Schema fallback behavior
Symptom: Warning falling back to langgraph.json names only or incomplete agent schemas.
Cause: Schema extraction failed or timed out, so AgentVisor falls back to just reading agent names from langgraph.json without full schema details.
Impact: The agent will still work, but:
- API documentation will be incomplete
- Input validation may be less strict
- A2A Agent Cards will have minimal skill descriptions
Fix:
- Run schema extraction manually to see the error:
python3 -m agentvisor.schema_cli --export . --output schema.json
- Fix any issues and cache the schema:
mkdir -p .agentvisorpython3 -m agentvisor.schema_cli --export . --output .agentvisor/schema.json
Schema cache staleness
Symptom: Agent changes aren't reflected in API documentation or tool schemas.
Cause: AgentVisor uses cached schema from .agentvisor/schema.json when it's newer than langgraph.json.
Fix:
- Delete the cached schema:
rm .agentvisor/schema.json
- Or regenerate it:
python3 -m agentvisor.schema_cli --export . --output .agentvisor/schema.json
- Restart the AgentVisor server
Tip: During active development, delete the cache directory to always use dynamic extraction:
rm -rf .agentvisor/
Getting Help
If your issue isn't covered here:
- Check the logs: Increase log verbosity with
AGENTVISOR_LOG_LEVEL=debug - Contact support: support@manetu.com — include logs, configuration (redact secrets), and steps to reproduce
See Also
- Configuration Reference: Full list of configuration options
- Local Development Setup: Debugging without sandbox isolation
- Policy Configuration: Writing authorization policies
- Temporal Configuration: Temporal setup guide
- MCP Gateway: Agent access to external MCP servers
- A2A Gateway: Agent access to external A2A agents