Skip to main content
The SDK raises only at construction time and at framework boundaries. The hot path (evaluate()) never raises — see Evaluation for why.
from rubric import (
    GovernanceError,
    GovernanceProblemError,
    ProblemDetails,
)
from rubric.adapters.langchain import GovernanceDeniedError

GovernanceError

Base class. Catch this if you want to handle anything from the SDK.
class GovernanceError(Exception):
    """Base class for all SDK exceptions."""

GovernanceProblemError

Raised when Rubric returns an RFC 9457 problem response (e.g., 401 invalid_identity, 403 forbidden, 429). Carries the parsed problem details.
class GovernanceProblemError(GovernanceError):
    problem: ProblemDetails
    status: int
class ProblemDetails(BaseModel):
    type: str          # URI identifier for the problem class
    title: str         # Short summary
    status: int        # HTTP status
    detail: str | None # Human-readable description
    instance: str | None
    # Plus typed extensions per problem type (retryAfter, etc.)

Typical sources

WhenLikely problem
Governance.bootstrap() with a bad tokeninvalid_identity (401)
Re-enrollment of a revoked identityforbidden (403)
Enrollment rate-limit exceededenrollment_rate_limited (429)
Token refresh after revocationinvalid_identity (401)

Example

from rubric import Governance, GovernanceProblemError

try:
    gov = Governance.bootstrap(agent_name="payments-bot")
except GovernanceProblemError as e:
    if e.status == 403:
        # Identity was revoked. Operator action needed.
        log.error("identity revoked: %s", e.problem.detail)
    elif e.status == 429:
        retry_after = e.problem.dict().get("retryAfter")
        log.warning("rate-limited; retry after %ds", retry_after)
    else:
        raise

GovernanceDeniedError (LangChain only)

Raised by the LangChain adapter when a tool call is denied. Subclass of PermissionError.
class GovernanceDeniedError(PermissionError):
    """Raised when a tool call is denied by an active policy."""
LangChain’s agent loop catches this and surfaces it as a tool failure to the model. You only catch it yourself if you want to handle denials specially. The MCP and Claude Agent adapters do not raise on deny — they return native tool-result shapes (isError=True / permissionDecision: "deny").

What does NOT raise

These are deliberately silent:
  • Evaluator failures. evaluate() returns default-allow; error is logged.
  • DLP detector failures. Treated as no-detection; error is logged.
  • Audit event flush failures. Events are retried; errors are logged.
  • Trace upload failures. Audit event still ships without traceId; error is logged.
  • Bundle pull failures. SDK keeps using last-known-good bundle; error is logged.
  • JWT refresh failures (transient). Retried with exponential backoff. Only after the JWT actually expires does the SDK surface a problem.
This is by design. A flaky network or a misconfigured Rubric should not stop your agent from doing its job.