Skip to main content

Error Handling

Governance decisions surface as Python exceptions. The SDK raises typed exceptions you can catch and handle in your agent code.

Import

from openbox_langgraph import (
GovernanceBlockedError,
GovernanceHaltError,
GuardrailsValidationError,
ApprovalRejectedError,
ApprovalExpiredError,
)

Governance Exception Hierarchy

ExceptionCauseDescription
GovernanceBlockedErrorBLOCK verdictOperation blocked by an OPA/Rego policy
GovernanceHaltErrorHALT verdictEntire agent session terminated by policy
GuardrailsValidationErrorGuardrails matchPII, toxic content, or restricted data detected
ApprovalRejectedErrorHITL rejectedA human rejected the approval request
ApprovalExpiredErrorHITL timeoutNo human decision before the approval deadline

All governance exceptions carry the human-readable decision message from OpenBox as the exception message (str(e)).

Handling Each Type

GovernanceBlockedError

Raised when a tool call or LLM invocation is blocked by policy. The graph execution stops at the blocked operation.

from openbox_langgraph import GovernanceBlockedError, create_openbox_graph_handler

governed = create_openbox_graph_handler(
graph=app,
api_url=os.getenv("OPENBOX_URL"),
api_key=os.getenv("OPENBOX_API_KEY"),
)

try:
result = await governed.ainvoke({"messages": [("user", input)]})
except GovernanceBlockedError as e:
logger.warning(f"Operation blocked by policy: {str(e)}")
# Return a safe fallback response
return {"response": "That action is not permitted."}

GovernanceHaltError

Raised when OpenBox issues a HALT verdict — the entire session is terminated, not just a single operation. Treat this as unrecoverable for the current session.

from openbox_langgraph import GovernanceHaltError

try:
result = await governed.ainvoke({"messages": [("user", input)]})
except GovernanceHaltError as e:
logger.error(f"Agent session halted: {str(e)}")
await notify_ops_team(str(e))
# Do not retry — start a new session if needed
raise

GuardrailsValidationError

Raised when a guardrail detects a policy violation — PII in a tool output, toxic content in an LLM response, or restricted data patterns.

from openbox_langgraph import GuardrailsValidationError

try:
result = await governed.ainvoke({"messages": [("user", input)]})
except GuardrailsValidationError as e:
logger.warning(f"Guardrail triggered: {str(e)}")
# Optionally inspect which guardrail fired
return {"response": "I can't process that content."}

ApprovalRejectedError

Raised when a human reviewer rejects the HITL approval request. The operation does not proceed.

from openbox_langgraph import ApprovalRejectedError

try:
result = await governed.ainvoke({"messages": [("user", input)]})
except ApprovalRejectedError as e:
logger.info(f"Human rejected approval: {str(e)}")
return {"response": f"Your request was reviewed and declined: {str(e)}"}

ApprovalExpiredError

Raised when no human decision is made before the approval deadline.

from openbox_langgraph import ApprovalExpiredError

try:
result = await governed.ainvoke({"messages": [("user", input)]})
except ApprovalExpiredError as e:
logger.warning(f"Approval timed out: {str(e)}")
# Retry or escalate
return {"response": "Your request is pending review. Please try again later."}

Catching All Governance Errors

For a single catch-all handler, use the OpenBoxError base class:

from openbox_langgraph import OpenBoxError

try:
result = await governed.ainvoke({"messages": [("user", input)]})
except OpenBoxError as e:
logger.warning(f"Governance decision: {type(e).__name__}: {str(e)}")
return {"response": "This action was not permitted."}

Configuration Exceptions

These are raised during create_openbox_graph_handler() — at initialization time, not during graph execution. Handle them where you set up your handler.

ExceptionCause
OpenBoxErrorBase class for all SDK errors
OpenBoxAuthErrorInvalid or missing API key
OpenBoxNetworkErrorCannot reach OpenBox Core
OpenBoxInsecureURLErrorHTTP used for a non-localhost URL
from openbox_langgraph import (
OpenBoxAuthError,
OpenBoxNetworkError,
OpenBoxInsecureURLError,
)

try:
governed = create_openbox_graph_handler(
graph=app,
api_url=os.getenv("OPENBOX_URL"),
api_key=os.getenv("OPENBOX_API_KEY"),
)
except OpenBoxInsecureURLError:
raise RuntimeError("OPENBOX_URL must use HTTPS in production")
except OpenBoxAuthError:
raise RuntimeError("Invalid OPENBOX_API_KEY — check your credentials")
except OpenBoxNetworkError as e:
raise RuntimeError(f"Cannot reach OpenBox Core: {e}")

Best Practices

  1. Catch GovernanceHaltError separately — it signals session termination; do not retry the same session
  2. Log governance exceptions — the message comes from your policy and aids debugging
  3. Provide fallback responses — not every block should surface as an unhandled exception to the user
  4. Clean up resources on HALT — release connections and notify downstream systems before exiting
  5. Never catch and ignore — governance exceptions are intentional decisions; swallowing them defeats the purpose

Debugging

Enable verbose SDK logging to trace governance decisions:

OPENBOX_DEBUG=1 python agent.py

This logs the full event payload sent to OpenBox and the raw verdict received, which helps diagnose unexpected blocks or missing events.

Next Steps

  1. Configuration — Configure on_api_error, timeouts, and HITL behavior
  2. Event Types — Understand the semantic event types that trigger governance decisions
  3. Approvals — Review and process HITL requests in the dashboard