Developer documentation
Troubleshooting
Last reviewed 31 August 2026
All docs
Start here:
cain doctor
It names the misconfiguration and prints the command that fixes it.
"not authenticated" / exit code 4#
cain login
If it still fails, the key may be valid but the subscription inactive -- that returns HTTP 402 and doctor reports it separately from a rejected key.
"could not reach the fabric" / exit code 3#
cain status cain connect --endpoint https://cainstudio.online
Exit code 3 is deliberately distinct from 1: an outage is not a policy refusal. When the fabric is unreachable every decision is ERROR, and under strict mode that means every guarded call refuses. That is intended -- a network failure between an agent and its authorization service is not consent.
Everything is allowed and I expected denials#
Likely one of three things, all of which cain doctor reports:
1. The deployment is in shadow mode. Decisions are recorded, nothing blocks. Check cain status for mode. 2. The stage you expected to block is advisory. cain status lists which stages are enforcing. 3. The stage is enforcing but has nothing loaded. doctor reports patterns_loaded: 0 for exactly this case -- enforcing with nothing to match.
Nothing is allowed#
policy.default: denywith no rules that permit your action.cain policy test
will tell you.
- A revoked principal.
cain doctorreports principal status. - The fabric is unreachable and strict mode is on -- see above.
UNKNOWN verdicts#
A stage could not answer. cain explain <id> names it. Common cause: the ActionProof or agent-id service is down; doctor checks dependency reachability.
UNKNOWN is refused rather than allowed by design. If you need the looser behaviour, enforcement.strict: false is the switch -- and doctor will warn about it for as long as it is off, because it converts "we could not check" into permission.
cain validate fails on a key I am sure exists#
Unknown keys are errors, not warnings. Run cain validate --list-keys for the accepted set. This is deliberate: a typo'd key that gets silently ignored is how a config ends up looking stricter than it is.
"MCP calls are not being decided"#
Your client is probably still reaching the server directly. Putting the gateway in the path does not remove the direct route -- bind the server to localhost or a network only the gateway can reach. cain doctor cannot detect this and does not claim to.
The signature changed between reads#
It should not; signing is deterministic. If it did, the decision record was altered, which is the property the signature exists to reveal. `cain test --suite evidence` checks this explicitly.