Skip to main content

Failure Behavior

Scope

Applies to DynamoGuard. For the platform layer beneath it, see Platform Reliability.

High availability and disaster recovery describe how the platform stays available. This page describes what happens to a single guardrail request when something it depends on is not.

Read this before integrating. The most important configuration decision for a protected workload is not made in the platform: it is made in the calling application, in how that application handles an error from the analyze endpoint.

The Platform Returns An Error, Not A Decision

When the platform cannot evaluate a policy, the analyze endpoint returns an HTTP error. It does not return an allow, and it does not return a block.

There is no fail-open or fail-closed setting. The calling application decides the posture by how it handles that error. An application that treats an error as a pass permits ungoverned content. An application that treats an error as a block does not.

Configure the calling application to fail closed

For any workload where unchecked content is unacceptable, treat every non-2xx response from POST /v1/moderation/analyze as a block. This is the only way to achieve fail-closed behavior in the current release.

if (response.status < 200 || response.status >= 300) {
// Treat as BLOCK. Do not forward the content.
}

A successful analyze returns 201. Check for a 2xx range; equality with 200 fails.

Dependencies On The Request Path

A single analyze call depends on all of the following. Any one of them being unavailable fails the request.

DependencyUsed forCached
KeycloakAuthentication and per-resource authorizationKeycloak-side only
MongoDBPolicy lookup, guardrail configuration, keyword listsNo. Read on every request
Moderation workerDispatching each policy to its model serverNo
Guardrail model serversOne inference per policy in the requestNo
Application PostgreSQLThe moderation log write, which precedes the responseNo

Object storage is not on the request path. Guardrail model weights load when a model pod starts. An object store outage does not fail requests that are already being served. It prevents new model pods from starting. That affects recovery and scaling, not serving. See Object Storage Availability.

What A Request Returns When A Dependency Fails

UnavailableResponseRecorded in the moderation log
Keycloak401 or 5xxNo
MongoDB5xxNo
Moderation worker5xxNo
One guardrail model server5xx for the whole request, including policies that succeededNo
Application PostgreSQL5xx, after the verdict was computedNo

Two consequences follow from this table and are worth stating plainly.

The policy fan-out is all-or-nothing. A request naming several policies dispatches one inference per policy. If any one of them fails, the whole request fails, including the policies that returned a result. Across separate requests the policies are independent.

A failed request produces no moderation log entry. The moderation log records completed evaluations. A period during which evaluation was failing appears in the log as an absence of entries, and that is indistinguishable from an absence of traffic. Detect degraded enforcement from the platform's request metrics. The moderation log will not show it. See Monitoring And Targets.

The Moderation Log Write Precedes The Response

The moderation log write is synchronous and happens before the response returns. A log store outage therefore fails a request whose evaluation already succeeded.

Two request-level controls exist:

FieldEffect
loggingControl.enabledDefaults to true. When false, the log write is skipped and a log store outage does not fail the request
loggingControl.forceLogOnFinalActionA list of final actions the server logs regardless of the setting above

Setting enabled to false trades the audit record for availability. For a regulated workload, the combination below is usually the correct one: keep a record of every decision that restricted content, and allow unrestricted content to proceed unlogged if the log store is unavailable.

{
"loggingControl": {
"enabled": false,
"forceLogOnFinalAction": ["BLOCK", "SANITIZE", "REDACT"]
}
}

Confirm the behavior you configured before relying on it, and record the choice: it changes what the audit trail contains.

A Policy That Cannot Be Resolved Is Omitted

This is the most important limitation on this page.

The analyze endpoint resolves each identifier in policyIds against the policy store. An identifier that does not resolve is omitted from the evaluation, and the request returns success with the remaining policies applied. The response does not warn that a policy was omitted.

A policy identifier fails to resolve when the policy has been deleted, or when the policy store the serving region reads does not hold it — for example a standby region whose policy set is behind the primary. A disabled policy behaves differently and correctly: the request fails with a 400 naming the policy.

Detect this in the calling application. The response carries appliedPolicies. Compare it against the identifiers sent:

POST /v1/moderation/analyze
{"policyIds": ["<id-a>", "<id-b>"], ...}

Response 201
{"finalAction": "NONE", "appliedPolicies": [ { "policy": { "id": "<id-a>" }, ... } ]}

Here <id-b> was not applied. Treat any request where appliedPolicies does not account for every identifier sent as an enforcement failure, and handle it as you would a 5xx.

A request naming no policies returns success

policyIds accepts an empty list, and a request that names no policies returns 201 with a final action of NONE, having applied nothing. Validate in the calling application that at least one policy identifier is present before sending, and apply the appliedPolicies check above to every response.

Cross-region behavior for this case, including why a policy count is not a parity check on its own, is in Traffic Routing.

Guardrail Serving Under Load And During Updates

PropertyBehavior
Replicas per guardrail modelOne by default. Configurable through replicas on the model
Disruption budgetCreated automatically when a model runs two or more replicas
Cold start60 to 300 seconds while a model loads, so capacity is pre-provisioned rather than autoscaled
Update strategyRolling. A new pod starts before the old one stops, which requires headroom for a second pod

A model running a single replica is unavailable for the duration of a restart, and every request naming its policy fails during that window. Run two or more replicas for any policy whose availability matters, which also creates the disruption budget.

Custom policy models are managed by the platform and run a single replica in the current release.