kosa8 docs

Guides / Agent troubleshooting

Agent troubleshooting

kosa8 refuses things on purpose, and each refusal says why. This page lists the messages word for word, grouped by where you meet them, with what each one means and what to do next. Search the page for a few words of the message you have.

The command line prints an error after the prefix kosa8:. Most examples below leave that prefix off and show the message itself. Where a message has a … in it, the real one carries a detail that differs from case to case.

How to see what happened

A refusal is shown to whoever caused it, which is often the agent and not you. These commands show you the same thing afterwards.

Where to look for each symptom Five symptoms, each joined to the command that explains it. A request from the sandbox failed: kosa8 sandbox egress NAME. A tool call was refused: kosa8 audit ls with the actor set to agent. A tool call is waiting: kosa8 mcp asks. A tool is missing from the list: kosa8 mcp pins diff SERVER. Policy said no and you want the rule: kosa8 mcp-policy events with the denied flag. A request from the sandbox failed a download, an API call, a DNS lookup kosa8 sandbox egress NAME the network rule, and counts of what it refused A tool call was refused the agent says kosa8 stopped it kosa8 audit ls --actor agent each decision, with the reason it gave A tool call is waiting the agent asks you to approve something kosa8 mcp asks the held calls, with their arguments A tool is missing from the list it was there yesterday kosa8 mcp pins diff SERVER definitions that changed, or are new Policy said no: which rule? you need the rule, the scope and the policy kosa8 mcp-policy events --denied every denial, one line each
Start from the symptom on the left.
CommandWhat it shows
kosa8 audit lsRecent audited actions, 25 by default. -n 100 for more, --actor agent (or human, tool) to filter.
kosa8 audit ls --jsonThe same entries in full, including detail and the structured refs: which agent, which rule, which host and path.
kosa8 audit verifyChecks that the log has not been altered: audit chain intact: 17 entries verified.
kosa8 sandbox egress NAMEThe network rule your computer enforces for that sandbox, and counts of what passed and what was refused.
kosa8 mcp asksTool calls waiting for a person, with the arguments as the agent sent them.
kosa8 mcp pins diff SERVERWhat changed in a tool server's withheld definitions.
kosa8 mcp-policy eventsMCP policy decisions. --denied for denials only, -n 20 for the latest, --format table to read (the default is jsonl; cef is there too).
$ kosa8 sandbox egress dev
policy:   allow:registry.npmjs.org (enforced on the host)
frames:   3 passed, 0 denied, 1 dropped as link noise
dns:      2 answered, 0 refused

Refused network requests appear in the audit log as sandbox.egress.deny, with the reason in the detail field:

sandbox.egress.deny  {"kind":"http","host":"neverssl.com","port":80,"method":"GET","path":"/","reason":"host not in allow-list"}
sandbox.egress.deny  {"proto":"dns","dst":"8.8.8.8","port":53,"name":"example.com","reason":"name not in egress policy deny"}

Starting an agent

Messages from kosa8 agent run, before the agent itself starts. Add --dry-run to see what a kit would do without creating anything.

The kit is unavailable

kosa8: kit cursor cannot be run as shipped: the npm package "cursor-agent" is not published by Cursor, so this kit no longer installs it; write a kit that installs Cursor's CLI from a source you have verified (`kosa8 agent init cursor`)

What it means. The built-in kit would have installed software kosa8 cannot vouch for, so it has been switched off rather than guessed at. kosa8 agent kits marks these UNAVAILABLE.

What to do. Copy the kit with kosa8 agent init KIT, point it at a source you have checked yourself, and pin the package. See Writing a kit.

The kit installs something that is not pinned

kit team installs software that is not pinned to a version and digest:
  …the setup lines in question…
list it under `packages:` with a version and integrity, or pass --allow-unpinned to run whatever the registry serves today

What it means. The kit's setup: downloads or installs something by name alone. What you get would be whatever the registry serves at that moment.

What to do. Move the install into the kit's packages: list with an exact version and its integrity digest. --allow-unpinned runs it anyway, and means what it says.

A package's checksum did not match

sha512sum: WARNING: 1 of 1 computed checksums did NOT match

What it means. The package that was downloaded is not the one the kit pinned. The run ends before the agent starts. Either the kit's digest is wrong, or the registry served different bytes for that version.

What to do. Do not work around it. Compare the version and integrity in the kit's packages: with what the publisher lists. If the kit is right, treat the download as suspect.

The kit file is unsigned

kosa8: warning: kit file ./team.yaml is unsigned: nothing vouches for its contents (sign it with `kosa8 agent sign`, and pin the key with `kosa8 policy trust`)
kosa8: warning: kit file ./team.yaml replaces the built-in kit of the same name

What it means. A warning, not a refusal. No organisation key is pinned on this machine, so the kit runs, and kosa8 tells you nobody has vouched for it. The second line appears when a file of yours has the same name as a built-in kit and is used in its place.

What to do. Read the kit before running it. To make this a guarantee, sign kits with kosa8 agent sign PRIVATE_KEY_FILE KIT_FILE and pin the public key.

The kit is not signed, on a machine that requires it

kit ./team.yaml is not signed, and this machine only runs kits signed by its org's key; have it signed with `kosa8 agent sign`
kit ./team.yaml does not match its signature: it was changed after it was signed, or signed with a different key
kit ./team.yaml is signed by a key this machine does not trust

What it means. Your organisation has pinned a signing key, so only kit files signed by it will load. The first message is a kit with no signature file beside it. The second is a kit that was edited after signing: the signature covers the exact bytes. The third is a valid signature by somebody else's key.

What to do. Ask whoever holds the organisation's key to sign the file as it is now. Editing a signed kit always means signing it again.

A key is not set on your computer

kosa8: warning: ANTHROPIC_API_KEY is not set on the host; the agent may fail to authenticate

What it means. The kit expects an environment variable that is empty in the shell you ran the command from. The sandbox starts anyway.

What to do. Export the variable in that shell and run again. With a brokered kit the value stays on your computer. See Keep API keys out.

The service did not start a broker

the daemon did not start an egress broker for this sandbox; restart it so it matches this kosa8 (`kosa8 daemon stop && kosa8 daemon start`)

What it means. The background service is older than the command you typed and does not know about brokered credentials. The sandbox it made was removed again, because it would have had no way to reach anything.

What to do. Run the two commands in the message.

Notices worth reading

kosa8: passing GITHUB_TOKEN into the sandbox as plain environment variables — the agent can read them
kosa8: network UNRESTRICTED — this kit sets no egress_allow

What they mean. Not errors. The first says a real key is inside the sandbox, because that tool cannot be pointed at the broker. The second says the kit names no hosts, so the sandbox can reach anything.

What to do. For the first, use a token with as little access as the job needs. For the second, add egress_allow to the kit, or run with --no-network.

Inside the sandbox

What the agent, or a tool it runs, sees when the network says no. A brokered sandbox has one way out: the proxy named in its HTTPS_PROXY variable. Refusals from that proxy are an HTTP status and one line beginning kosa8:.

Busybox wget (alpine's) got 400 Bad Request for every HTTPS address before kosa8 0.9.36: it has no CONNECT and asks the proxy for GET https://host/path instead. From 0.9.36 the broker forwards that form, under the same allow-list, making the TLS connection and checking the certificate itself.

The host is not on the list

HTTP/1.1 403 Forbidden
kosa8: neverssl.com is not in this sandbox's egress allow-list; add it to the sandbox's egress policy (an exact name does not cover its subdomains)

What it means. The sandbox asked for a host its rule does not name. Listing example.com does not allow api.example.com; that needs its own entry or *.example.com.

What to do. If the host is needed, add it to the kit's egress_allow or the sandbox's --egress-allow. If it is not, the rule is working. See Network rules.

The host is allowed, but not like that

kosa8: api.example.com is allowed, but not on port 8443; use an allowed port or add this one to the egress policy
kosa8: DELETE is not an allowed method for api.example.com; allowed: GET, POST
kosa8: example.internal resolves to a private, loopback or link-local address, which a name may not stand for; if that host is meant, list its IPv4 address in the egress policy

What it means. The name matched and something else did not: the port, the HTTP method, or where the name leads. The third message is a guard against a public name being pointed at something on your own network.

What to do. Widen the rule only if the request is one you intended. For a host that really is on your private network, list its address rather than its name.

A credential route refused the request

HTTP/1.1 403 Forbidden
kosa8: this route needs the sandbox's placeholder credential

HTTP/1.1 400 Bad Request
kosa8: the placeholder credential also appears in …; it belongs only in the x-api-key header

HTTP/1.1 405 Method Not Allowed
kosa8: route anthropic does not allow DELETE; allowed: POST

HTTP/1.1 403 Forbidden
kosa8: route anthropic does not allow this path; allowed prefixes: /v1/messages

HTTP/1.1 400 Bad Request
kosa8: path has a . or .. segment; send the plain path the API documents

HTTP/1.1 404 Not Found
kosa8: no such route; the first path segment must be one of: anthropic

What it means. A route is the address the sandbox uses to spend a key it does not hold. The sandbox is given a stand-in value, the placeholder, and the broker swaps it for the real key on the way out. Each message is one of the route's checks: the placeholder is missing or wrong; the placeholder was also sent somewhere it should not be, such as the URL; the method is not one the route permits; the path is outside its prefixes; the path tries to climb with ..; or the route's name is wrong.

What to do. Usually nothing: the agent's tool is being held to the route the kit declared. If a legitimate call is refused, widen methods: or paths: for that credential in the kit. A wrong placeholder after you edited the environment by hand means you should let kosa8 agent run set it.

The broker is busy, or the far end is down

kosa8: this sandbox already has N requests and tunnels open through the broker; close idle connections or retry shortly
kosa8: api.example.com is allowed but could not be reached on port 443; check the host is up, then retry
kosa8: the upstream is allowed but did not answer; check it is reachable from the host, then retry
kosa8: this sandbox's egress broker has shut down; restart the sandbox's network to reach anything

What it means. Nothing was refused by policy. The first is a limit on simultaneous connections (HTTP 503). The next two mean your computer could not reach the destination (502). The last means the sandbox outlived its broker.

What to do. Retry, and check the destination from your own terminal. A brokered sandbox that was stopped and started, restored or copied comes up with its network closed and no broker, because the keys lived only in the service's memory. Start a fresh one with kosa8 agent run.

Going round the proxy

# a direct connection to 1.1.1.1, bypassing the proxy
Connection refused
# nslookup example.com
server can't find example.com: REFUSED

What it means. A program ignored the proxy and tried to connect directly, or to look a name up itself. The network guard on your computer refused the packet. The exact wording belongs to the program; "connection refused" and DNS "REFUSED" are the signs.

What to do. Make the program use the proxy; most honour HTTPS_PROXY. kosa8 sandbox egress NAME shows the counts, and the audit log has each attempt with "reason":"not in egress policy deny".

A sandbox the agent made has no network

What it means. A sandbox created by an agent through the sandbox_create tool has no network unless the agent asks for one. Image pulls still work, because the service fetches images on your side.

What to do. The agent names the hosts it needs in egress_allow, or asks for egress: "any". Asking for both is refused: egress_allow already limits the network to the hosts it lists; do not also set egress to "any".

An AI client calling a tool

Most of these come back to the agent as the tool's result, beginning kosa8:. The agent usually repeats them to you.

The call needs a person

kosa8: deploys are reviewed — this call needs a person's approval and you cannot give it. Ask a person to review it with `kosa8 mcp asks` and approve it with `kosa8 mcp approve 3f2a9c0d1e4b5a67`, then make exactly the same call again

What it means. A rule answered "ask". The call is held, not denied. The text before the dash is the rule's reason.

What to do. Run kosa8 mcp asks, read the arguments, then kosa8 mcp approve ID or kosa8 mcp refuse ID. Tell the agent to make the same call again. The approval lasts ten minutes and is used once. See Rules for tool calls.

Approving did not work

`kosa8 mcp approve` must be run by a person at a terminal
no held call 3f2a9c0d1e4b5a67; list them with `kosa8 mcp asks`
held call 3f2a9c0d1e4b5a67 expired; have the agent make the call again
held call 3f2a9c0d1e4b5a67 was already approved

What it means. In order: the command was run through a pipe or by a script; the id is wrong, or the question lapsed and was cleared; the question waited more than an hour; it has been answered already.

What to do. Run it yourself in a terminal, with the id from kosa8 mcp asks. If the agent says it is still waiting after you approved, it changed the arguments: a different call is a different question.

A person said no

kosa8: a person refused this call (held call 3f2a9c0d1e4b5a67): deploys are reviewed

What it means. Somebody ran kosa8 mcp refuse for this exact call. The refusal stands until the original question's hour runs out.

What to do. Nothing, unless it was a mistake. A different call is a new question.

The arguments do not fit the tool

kosa8: the arguments do not match the schema echo/echo was approved with: …

What it means. The agent sent arguments the tool's pinned schema does not accept: a missing required field, a wrong type, or a field the tool never asked for. The server never saw the call.

What to do. The agent should read the rest of the message and correct the call. If the server's schema really changed, see "withheld" below.

The tool's answer was withheld

kosa8: echo/echo returned a result that does not match the output schema it declared, so it was withheld: …

What it means. The tool ran, and answered outside its own contract. The answer was not passed to the model.

What to do. This is the tool server's fault, not the agent's. Report it to whoever maintains the server. Note that the tool did run.

A rule denied the call

kosa8: do not echo secrets
kosa8: tool "delete_repo" on server "github" is denied for scope "engineering" by rule deny_tools "delete_*"
kosa8: tool "create_repo" is not in the allowlist for server "github" in scope "engineering" (allowed: list_*, get_*, search_*)

What it means. The first is an argument rule: the text is whatever its author wrote as the reason. The second and third are the tool lists. They are met at call time for kosa8's own tools, and when a client calls a third-party tool it was never offered.

What to do. The reason is the instruction. If the rule is wrong, the policy has to be changed and signed again by whoever holds the key; nothing on your machine can override it.

The rule fired because an argument could not be read

kosa8: …the rule's reason… [argument "/limit" could not be evaluated by "gt": it is a string, and this operator needs a number, so the rule was applied rather than risk letting the call through; send that argument in the type the tool's schema declares]

What it means. A rule compares a number and the agent sent text, or the other way round. kosa8 cannot tell whether the rule applies, so it applies it.

What to do. The agent sends the argument in the right type: 5000, not "5000".

The server or the scope is not approved

MCP server "randomvendor" is not approved for scope "engineering"; approved servers: docs, github — ask your admin to add it to the org policy
scope "relase" is not defined in policy "example-corp" (defined: engineering, release); see `kosa8 mcp-policy scopes`
no scope was given and policy "example-corp" sets no default_scope; pass --scope or have your admin set one

What it means. Under a signed MCP policy, a tool server nobody listed is denied. The second message usually means an agent identity was created with a mistyped --scope. The third means the gateway has no identity and the policy has no default.

What to do. For the first, ask for the server to be added. For the second, revoke the identity and create it again with a scope from kosa8 mcp-policy scopes. For the third, give the gateway an identity. See Agent identity.

The policy itself is broken

the installed MCP policy failed verification: signature does not match MCP policy (tampered or wrong key); re-install a policy signed by your org with `kosa8 mcp-policy install`
a trusted policy signer is pinned but no MCP policy is installed (was it deleted?); re-install it with `kosa8 mcp-policy install`
the tool-call rule set is invalid, so every call is denied: … — fix the org policy and re-sign it

What it means. Every call is denied until the policy is whole again. An edited, deleted or malformed policy locks the door rather than opening it.

What to do. Install the signed policy again. See Company rules.

Sharing a folder was refused

host mounts are disabled for MCP agents: ask the user to restart `kosa8 mcp serve` with --allow-mount DIR (or DIR:rw) naming the directories a sandbox may share
mount host path "/Users/you/other" is outside the directories this MCP server allows (--allow-mount)
mount host path "/Users/you/code" may only be shared read-only (the user allowed it without :rw)

What it means. An agent may share a folder of yours into a sandbox it creates only if you named that folder when you started the gateway.

What to do. Restart the gateway with --allow-mount DIR, or DIR:rw if the agent should be able to write there. Name the narrowest folder that does the job.

Starting the gateway

Printed by kosa8 mcp serve on standard error. If your AI client hides that output, run the command by hand in a terminal to read it.

A tool was withheld

kosa8 mcp gateway: echo: tool "echo" withheld: its definition changed since it was pinned (sha256:…, now sha256:…) (review with `kosa8 mcp pins diff echo`, accept with `kosa8 mcp pins approve echo`)
kosa8 mcp gateway: echo: tool "upload" withheld: it is new since this server's tools were pinned (review with `kosa8 mcp pins diff echo`, accept with `kosa8 mcp pins approve echo`)

What it means. The server now describes a tool differently from when you approved it, or offers one it did not offer before. Until a person accepts the change, the model is not shown that tool.

What to do. Run kosa8 mcp pins diff SERVER and read the old and new descriptions. If the change is one you expected, such as after an upgrade, kosa8 mcp pins approve SERVER and restart the gateway. If not, stop using the server. See Tool servers.

A tool was withheld by your organisation's pins

kosa8 mcp gateway: github: tool "create_gist" withheld: the org policy pins this server's tools and does not list this one (the org policy's pins decide this; ask your admin)
kosa8 mcp gateway: github: tool "create_issue" withheld: its definition (sha256:…) is not the one the org policy pins (sha256:…); the server changed it, or the policy needs re-signing (the org policy's pins decide this; ask your admin)

What it means. The signed policy fixes this server's tool definitions. Nothing can be approved locally.

What to do. Send your administrator the output of kosa8 mcp pins show SERVER from a machine where the new version was reviewed.

A tool's schema cannot be checked

kosa8 mcp gateway: vendor: tool "search" withheld: its input schema cannot be enforced: …

What it means. The schema refers to something off your machine, recurses without end, or nests too deeply to check safely. A tool whose arguments cannot be checked is not offered.

What to do. Report it to the server's maintainer. There is no override.

A server exposed nothing, or did not start

kosa8 mcp gateway: github: exposed none of 26 tools (0 excluded by the allowlist, 0 collided with existing tool names, 26 denied by org MCP policy, 0 withheld because their definitions are not the pinned ones or cannot be checked) (skipped)
kosa8 mcp gateway: github: tool "github_status" collides with an existing tool, skipping
kosa8 mcp gateway: github: mcp handshake: … (skipped)

What it means. The first line counts which filter removed each tool, because each has a different fix: your own --allow-tool list, a clash of names, the organisation's policy, or pins. The last is a server that crashed or never spoke MCP. A skipped server never stops the gateway or kosa8's own tools.

What to do. Follow the largest number. For a handshake failure, check the command with kosa8 mcp ls, and whether the server needs a host its network rule does not allow (a server started with npx needs its package registry).

The gateway must identify itself

the org policy requires agents to identify themselves: mint a token with `kosa8 agent token create NAME` and start this gateway with KOSA8_AGENT_TOKEN set to it

What it means. Your organisation's policy sets require_agent_identity, and this gateway was started with no token.

What to do. Create an identity and put its token in the gateway's environment. See Agent identity.

The token was not accepted

the daemon did not accept the agent token: agent token is not recognised; mint one with `kosa8 agent token create NAME`
the daemon did not accept the agent token: agent reviewer (agt_…) was revoked on 2026-…; mint a new token with `kosa8 agent token create`
the daemon did not accept the agent token: agent reviewer (agt_…) expired on 2026-…; mint a new token with `kosa8 agent token create`

What it means. The token is mistyped or cut short, belongs to another machine's registry, was revoked, or has passed its lifetime. A bad token is refused outright; the gateway is not allowed to carry on as an anonymous agent.

What to do. kosa8 agent token ls shows the state of each identity. Create a new token and restart the gateway. Tokens are shown once, so a lost one is replaced, not recovered.

The gateway will not listen there

refusing to serve MCP on 0.0.0.0:7433: it is not a loopback address, and anyone who can reach it can run containers on this machine. Bind 127.0.0.1 (e.g. --http 127.0.0.1:7433), or pass --insecure-listen if it is fronted by something you trust
unauthorized: send Authorization: Bearer <token> (printed by kosa8 mcp serve, or KOSA8_MCP_TOKEN)

What it means. The first is the gateway declining to listen on an address other machines can reach. An address with no host, such as :7433, counts as every interface. The second is an HTTP client that sent no token or the wrong one.

What to do. Bind 127.0.0.1. Give the client the token printed at start, the value of KOSA8_MCP_TOKEN, or, for an identified gateway with no KOSA8_MCP_TOKEN, the agent token.

The service is not running

kosa8 daemon unreachable (start it with `kosa8 daemon start`)

What it means. The gateway is only a door. The work is done by the background service, and it is not answering.

What to do. kosa8 daemon start, then kosa8 daemon status. If it will not stay up, see When something is wrong.

A decision could not be written down

kosa8 mcp gateway: echo/echo: decision not anchored in the audit log: …

What it means. The gateway decided a call and could not record the decision in the audit log, usually because the service was unreachable at that moment. The decision itself stood.

What to do. Check the service. A line is still written to the flat decision file that kosa8 mcp-policy events reads, without an audit sequence number.

Company policy

Refusals that come from the organisation's signed policy. None of these can be changed from the machine that shows them. What each field does is in Policy reference.

The registry is not allowed

policy "example-corp" forbids registry "quay.io" (allowed: docker.io, ghcr.io)

What it means. allowed_registries lists where images may come from, and this image is from somewhere else. The check applies wherever an image is fetched: a pull, a run that needs a missing image, a build's base image, and the Docker-compatible API.

What to do. Use an image from a listed registry, or ask for the registry to be added.

The tool server's image is not allowed

policy "example-corp" forbids MCP image "alpine" (allowed: node:22-alpine)

What it means. allowed_mcp lists the images that may run as tool servers. It is checked by kosa8 mcp add and again when the gateway starts the server. The comparison is on the whole image name.

What to do. Register the server with a listed image, written exactly as the policy writes it.

Containers must run in a sandbox

policy "example-corp" requires containers to run in a sandbox, and this would run on the shared engine; use `kosa8 sandbox create` and `kosa8 sandbox run`

What it means. require_sandbox is set, so kosa8 run, the container_run tool and the Docker-compatible API refuse to use the shared engine.

What to do. Create a sandbox and run the container inside it, as the message says. An agent uses sandbox_create and sandbox_run.

Agents must identify themselves

the org policy requires agents to identify themselves, and this request carries no agent token

What it means. The service's own version of the gateway message above, answered with HTTP 401 to any request that says it is from an agent and carries no token. It is recorded in the audit log as agent.auth.refused.

What to do. Give the agent's gateway a token.

Creating an identity was refused

an agent cannot mint agent identities
an agent named "reviewer" already has a live token (agt_…); revoke it first with `kosa8 agent token revoke reviewer`
a token may live at most 365 days; rotate longer-lived identities
Governance needs a subscription

What it means. In order: an agent tried to create an identity, which only a person may do; the name is in use by a live identity; the lifetime asked for is too long; creating identities is part of the Governance subscription. Listing and revoking never need one.

What to do. Run the command yourself; revoke the old token first; ask for a shorter --ttl; or start a trial.

The organisation policy does not verify

org policy present but failed verification, refusing to run: …
org policy present but failed verification, so an unidentified gateway cannot be started: …
no trusted policy signer is pinned, so any key would be accepted here — pin your org's public key first with `kosa8 policy trust <PUBLIC_KEY>`

What it means. The policy file on this machine was edited, or is signed by a key this machine does not trust. kosa8 treats every requirement in it as set and refuses. The last message is different: it appears when installing a policy before pinning who may sign one.

What to do. Install the signed policy again with kosa8 policy install. For the last message, pin the key first. Both are covered in Company rules.

What this page does not cover

  • Messages written by the tools themselves. An agent's own CLI, a tool server and curl each word their failures their own way; only the lines beginning kosa8: are kosa8's.
  • Requests that were allowed. A tunnel to an allowed host is opaque: kosa8 records the host and port, and cannot say what was sent through it.
  • Why a model chose to make a call. The audit log records what was asked and what was decided, with digests of the arguments, not the arguments.

Where to go next