Fail-open
The golden rule: TokenPolice never throws into your app except one designed case.
Golden rule: TokenPolice never breaks your app. A firewall that takes your app down when it has a problem is worse than no firewall — so if anything goes wrong on TokenPolice's side, the SDK swallows it and lets your LLM call proceed.
What "fail-open" means in practice
If the collector is slow, unreachable, misconfigured, or returns an error — a timeout, a network blip, a bad API key — the SDK does not raise. It logs the problem (if you asked it to) and your call runs exactly as it would without TokenPolice. Your users never see a TokenPolice error because of TokenPolice's trouble.
The one exception
There is exactly one error the SDK will ever throw into your code: TokenPoliceBlockedError.
It's raised only when a rule you configured decides to block and both dials are set to
enforce (dry-run vs enforce). That's not a failure — it's
the firewall doing the job you asked for.
try:
reply = run_agent(...)
except tp.TokenPoliceBlockedError as e:
# a rule you set is enforcing and chose to block this call
return "You've hit your usage limit for now."The error carries structured fields so you can react precisely: reason, rule_id, kind
(which rule type fired), and trace_id. Full contract in
Errors.
TokenPoliceBlockedError is a deliberate block, not a fault. Everything else —
every timeout, outage, or config mistake — is silently allowed through. If you're seeing this
error, a rule wanted to stop the call.
One deliberate exception, the other way round: on a long-running server, a block already in force stays in force. If a user or conversation has already been blocked and TokenPolice then goes unreachable, that block holds under enforce — an outage can't be used to lift a limit you set. New decisions still fail open.
This depends on the SDK holding an open stream of rule and blocked-set updates, which it does
only when deployment resolves to "daemon". On "serverless" and "edge" there is no
stream — every decision is an inline /check, so during an outage everything fails open,
including a block that was already in force. If that matters for your workload, keep the
enforcing path on a daemon deployment.

