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
memory_limit,cpu_limitandpids_limitare applied by thedockersandbox, and by thegvisorsandbox only when the host runtime runs as root with a writable cgroup v2 mount. In the default rootlessgvisordeployment they are not enforced (the startup log showsresource_limits=false, and a warning names any limit you changed); set memory, CPU and PID limits on the container or pod that runs the host runtime instead.
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
Outbound Destination Blocked
Requests through the outbound HTTP proxy pass through two independent checks before reaching their destination — see Egress Controls for the full model. The entries below map each observed failure back to the layer that produced it.
Request fails with an empty 502
Symptom: The agent's HTTP call returns 502 with an empty response body, and
there is no error detail available to the agent's own code.
Cause: This is by design, not a bug. The host's dial-time SSRF guard blocked the resolved address, but the denial reason is never returned to the guest — it exists only in the host's log.
Fix: Search the host log for the exact destination address the guard rejected:
destination address is not permitted for outbound proxy requests: ::1
Add the named address to proxy.ssrf_allowed_cidrs — or, for a hostname target, add
every address family it can resolve to. See
Granting an Exemption.
Request fails with 400 bad request
Symptom: The agent's HTTP call returns 400 with a generic bad request body,
regardless of what is configured in proxy.ssrf_allowed_cidrs.
Cause: The request names a blocked address as an IP literal directly in the
URL (for example http://169.254.169.254/ or http://10.0.5.7:8080/). A guest-side
check rejects this before the request ever leaves the sandbox, and that check has no
visibility into proxy.ssrf_allowed_cidrs at all — allowlisting the address does not
change this outcome.
Fix: Address the upstream by hostname instead of by IP literal. The same
destination reached through a hostname is evaluated by the allowlist-aware host-layer
guard against the address it actually resolves to, so an ssrf_allowed_cidrs entry can
take effect. See
Two Enforcement Layers, and the Asymmetry.
localhost still blocked after allowlisting 127.0.0.1
Symptom: proxy.ssrf_allowed_cidrs includes 127.0.0.1/32, but a request to
http://localhost:11434/ still fails with an empty 502.
Cause: localhost resolves to both 127.0.0.1 and ::1 on a dual-stack
host, and the guard rejects the entire dial if any one resolved candidate is blocked.
Allowlisting only the IPv4 address leaves the IPv6 candidate unlisted, so the whole
request is still rejected.
Fix: Either list both address families:
proxy:
ssrf_allowed_cidrs:
- "127.0.0.1/32"
- "::1/128"
or use the hostname form, which resolves once at startup and allowlists every address it finds:
proxy:
ssrf_allowed_cidrs:
- "localhost"
Startup fails: invalid entry
Symptom: agentvisor serve exits immediately with an error naming an
ssrf_allowed_cidrs entry, followed by the command's usage text. This happens before
logging initializes, so it will not appear in a structured-log-only capture.
Cause: A comma-separated AGENTVISOR_PROXY_SSRF_ALLOWED_CIDRS value has a space
after a comma. Entries are not trimmed, so the space becomes part of the following
entry:
AGENTVISOR_PROXY_SSRF_ALLOWED_CIDRS="127.0.0.1/32, ::1/128"
produces exactly:
Error: failed to load config: proxy config: proxy.ssrf_allowed_cidrs: invalid entry " ::1/128": must be a CIDR range, an IP address, or a hostname
Fix: Remove the space after every comma:
AGENTVISOR_PROXY_SSRF_ALLOWED_CIDRS="127.0.0.1/32,::1/128"
Allowlist entry appears accepted but has no effect
Symptom: Startup succeeds, but an entry added to ssrf_allowed_cidrs doesn't seem
to exempt anything.
Cause: A hostname entry is checked for syntax at config-load time only — not for resolvability. An entry that looks like a hostname but doesn't actually resolve (a malformed IP address, a typo, a name that no longer exists) is silently skipped: startup still succeeds, with a warning naming the entry:
ignoring unresolvable proxy.ssrf_allowed_cidrs hostname entry {"host": "999.999.999.999", "error": "lookup 999.999.999.999: no such host"}
Fix: Search the startup log for ignoring unresolvable proxy.ssrf_allowed_cidrs hostname entry and correct the named entry.
Request to 127.0.0.1 succeeds when it was expected to be blocked
Symptom: A request to a literal http://127.0.0.1:<port>/ URL succeeds even
though ssrf_allowed_cidrs doesn't list it — unlike any other loopback-range IP
literal, which is rejected with 400.
Cause: AgentVisor sets NO_PROXY=127.0.0.1 in every agent's own environment, and
standard proxy-aware HTTP clients (requests, httpx, curl, and effectively every
other proxy-respecting client) honor NO_PROXY by connecting directly — bypassing the
proxy, the SSRF guard, and policy entirely — for a request whose host is the literal
string 127.0.0.1. This is a client-side bypass, not an allowlist grant. It has been
observed under --sandbox=none, where the bypassed connection reaches the host's own
real loopback interface.
Fix: This is expected behavior, not a misconfiguration. If this traffic needs to
actually go through the proxy — for policy enforcement, credential substitution, or the
SSRF guard to apply — address the upstream by a hostname other than the literal string
127.0.0.1, or run under --sandbox=gvisor or --sandbox=docker, where the guest's
own network namespace means 127.0.0.1 refers to the guest's isolated loopback rather
than the host's.
See Egress Controls for the full mechanism.
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
Gateway Issues
Issues below apply to both the MCP Gateway (agent access to external MCP servers) and the A2A Gateway (agent access to external A2A agents) — they share the same pool and credential-resolution machinery, differing only in config key and (for A2A) protocol-specific error codes.
Connection pool exhausted
Symptom: Error connection pool exhausted or too many connections.
Cause: The number of concurrent principal-bound connections exceeds the pool limit.
Fix: Increase the pool size:
| Gateway | Config key | Default |
|---|---|---|
| MCP | mcp.pool.max_size | 100 |
| A2A | a2a_gateway.pool.max_size | 100 |
mcp:
pool:
max_size: 200 # Default: 100
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 and don't consume pool slots.
Idle timeout
Symptom: 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:
| Gateway | Config key | Default |
|---|---|---|
| MCP | mcp.pool.idle_timeout | 5m |
| A2A | a2a_gateway.pool.idle_timeout | 5m |
mcp:
pool:
idle_timeout: 15m # Default: 5m
a2a_gateway:
pool:
idle_timeout: 15m # Default: 5m
Note: Longer timeouts consume more resources. If agents call a given server/agent sporadically, shorter timeouts with automatic reconnection may be more efficient.
Credential resolution failures
Symptom: Error failed to resolve credentials for MCP server / failed to resolve credentials for A2A agent, or token exchange failed.
For bearer_token resolver:
- Verify the environment variable is set (e.g.
echo $GITHUB_TOKENfor MCP,echo $RESEARCH_AGENT_TOKENfor A2A) - Check the configuration matches — MCP example:
A2A example:mcp:servers:- name: githubcredentials:type: bearer_tokensource: envenv_var: GITHUB_TOKEN # Must match actual env vara2a_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:
credentials:type: token_exchangeexchange_url: "https://auth.example.com/token"audience: "github-mcp" # Must match server's expected audience
Upstream JSON-RPC error codes (A2A only)
The A2A Gateway client maps a subset of A2A's implementation-defined JSON-RPC error codes to a normalized error class; 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 | Normalized by the gateway |
-32002 | Unauthorized | Normalized by the gateway |
-32003 | Forbidden | Normalized by the gateway |
-32004 | Conflict | Passed through as a raw JSON-RPC error with the upstream's code and message |
-32005 | Service unavailable | Normalized by the gateway |
-32006 | Operation timed out | Normalized by the gateway |
-32007 | Invalid task state | Normalized by the gateway |
-32008 | Agent not found | Passed through as a raw JSON-RPC error with the upstream's code and message |
-32009 | Message rejected | Passed through as a raw JSON-RPC error with the upstream's code and message |
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
- Egress Controls: The policy gate and SSRF guard that govern outbound requests
- 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