Guard Error Handling
When the Anthropic or OpenAI integration is enabled, a blocked tool call raises staso.GuardBlocked.
import staso as st
from staso.integrations import patch_anthropic
import anthropic
st.init(api_key="...", agent_name="refunds-agent")
patch_anthropic()
client = anthropic.Anthropic()
try:
resp = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[...],
messages=[...],
)
except st.GuardBlocked as e:
for bt in e.blocked_tools:
print(f"blocked {bt.tool_name}: {bt.result.reason}")
# fall back or ask the userThe integrations evaluate every tool call in the batch before raising, so you see all failures, not just the first.
GuardBlocked fields
| Field | Type | Description |
|---|---|---|
tool_name | str | Name of the first tool that was blocked. Handy for one-line error messages. |
result | GuardResult | The full GuardResult for that first tool. |
reason | str | Short human-readable reason. When multiple tools are blocked, this summarises all of them. |
rules_triggered | list[str] | Deduplicated union of every rule name that contributed across all blocked tools. |
blocked_tools | list[BlockedTool] | Ordered list of every blocked tool in the batch. Iterate this for per-tool detail. |
BlockedTool is a small frozen dataclass:
| Field | Type | Description |
|---|---|---|
tool_name | str | The blocked tool's name. |
result | GuardResult | The full GuardResult for that tool. |
Patterns
Recover gracefully. Catch GuardBlocked, log the reason, and return a safe default or user-facing message. Never let it crash the outer request handler.
Fall back to a safer tool. If send_email was blocked for containing PII, try send_email_redacted. Structure your agent prompts so a fallback path exists.
Log and alert. Push e.rules_triggered and e.blocked_tools into your logger or alerting pipeline. Frequent blocks mean either a misbehaving agent or an over-eager rule — both worth knowing.
Re-ask the user. Surface e.reason back into your chat UI: "I can't do that because <reason>. Want me to try something else?"
Transport failures
If Guard itself is unreachable (network down, timeout, backend error), Guard fails open by default — the tool call is allowed and no exception is raised. The philosophy: a flaky observability backend should never brick production agents.
Override per call:
result = st.guard("delete_user", {"id": "u_42"}, fail_closed=True)Or process-wide:
export STASO_GUARD_FAIL_CLOSED=1With fail_closed=True, a transport failure returns action="block" with severity="high" and a reason like "Guard unavailable (fail-closed): <error>". In the patched integrations this path raises GuardBlocked, so wrap your client calls in try/except as shown above.
Next
- Actions and Escalation — what
block,modify, andescalatemean in practice. - Manual Guard Checks — the full
st.guard(...)API. - Troubleshooting
Actions and Escalation
Guard returns one of four actions — allow, block, modify, or escalate — and tells your code exactly what to do next, including synchronous human-in-the-loop escalation.
Datasets Overview
Curate production traces into versioned eval datasets and run your agent against them with custom scorers — all from the Staso Python SDK.