Security & Troubleshooting

The endpoint creates and deletes data, so it’s protected by three independent layers and two separate secrets. This page also collects every error code and the fixes for the problems you’re most likely to hit.

The two secrets

Two secrets with different jobs. They must be different values. The SDK does not check this at startup - it returns SAME_SECRETS (HTTP 500) on the first request that arrives, so a handler with matching secrets boots cleanly and fails on first use.

SecretEnv variableWho knows itPurpose
Shared secretAUTONOMA_SHARED_SECRETYou + AutonomaHMAC-signs every request. Autonoma signs; your SDK verifies.
Signing secretAUTONOMA_SIGNING_SECRETYou, and Autonoma when it manages your previewSigns the teardown token during up, verifies it during down.
Terminal window
openssl rand -hex 32 # AUTONOMA_SHARED_SECRET
openssl rand -hex 32 # AUTONOMA_SIGNING_SECRET (must differ)

The three layers

Three layers protect the endpoint: a production guard, request signing, and a signed teardown token

Layer 1 - Production guard (yours). Running on Autonoma preview environments (AUTONOMA_PREVIEWKIT is set in every preview)? Skip this layer entirely - previews are isolated, disposable, and never production. Deploying the factory in your own environments? Only mount the route outside production, with a condition you own:

if (process.env.NODE_ENV !== 'production') {
app.post('/api/autonoma', createHandler({ ... }))
}

The SDK itself has no switch here - the guard is plain code in your app, so you can see exactly when the endpoint exists at all.

Layer 2 - Request signing (HMAC-SHA256). Every request carries an x-signature header: the HMAC-SHA256 of the raw body, keyed with the shared secret. The SDK verifies it automatically and rejects unsigned or tampered requests with 401. Even someone who finds the URL gets nothing without the shared secret.

Layer 3 - Signed refs token. When up creates data, the SDK signs the created record IDs into a refsToken using the signing secret. On down, it verifies that token before deleting anything - so down can only ever delete what up actually created. Autonoma just stores the opaque string and passes it back; it cannot forge or modify it.

AttackWhy it fails
Fake refs with made-up IDsNo valid token → rejected
A real token with altered refsRefs don’t match the token → rejected
A replayed tokenConfined to the exact record IDs up signed into it - it can never delete anything else

What the SDK can and cannot do

  • up can only create. It invokes the factories you registered, which call your own services. It cannot update, delete, drop, truncate, or run raw SQL outside your factory bodies.
  • down can only delete what up created, verified by the signed token. It calls each factory’s teardown in reverse order.
  • The SDK never runs SQL itself. It calls your factories; they use whatever client your app already has.

Error codes

Every code the endpoint can return, with its fix:

CodeHTTPMeaningFix
CONFIGURATION_ERROR503The handler is running without AUTONOMA_SHARED_SECRET and AUTONOMA_SIGNING_SECRET. Not emitted by every SDK - the TypeScript one fails differentlySet both in the environment where your backend actually runs - setting them locally but not in the deployed service is the usual cause
INVALID_SIGNATURE401HMAC signature missing or doesn’t matchMake AUTONOMA_SHARED_SECRET match the value Autonoma uses for your app
UNRESOLVED_TOKEN400A {{token}} in the recipe’s create has no matching entry under variablesDeclare the variable, or fix the typo. Only {{testRunId}} and {{testRunShortId}} are built in
INVALID_BODY400Body isn’t valid JSON, a required field is missing, or a _ref names an alias nothing declaresMatch each record to its own top-level model key, supply every required field, and declare each alias with _alias in the same payload
UNKNOWN_ACTION400action isn’t discover, up, or downCheck the request is one of the three actions
UNKNOWN_ENVIRONMENT400The requested environment name does not existUse a scenario name your recipe actually declares
INVALID_REFS_TOKEN403Refs token missing, malformed, or failed verificationUse the same AUTONOMA_SIGNING_SECRET between up and down
PRODUCTION_BLOCKED404Older SDK versions only: the deprecated allowProduction option was not setUpgrade the SDK (the endpoint is always enabled now), or set allowProduction: true until you can
SAME_SECRETS500sharedSecret and signingSecret are identicalUse two different openssl rand -hex 32 values
FACTORY_MISSING_PK500A factory’s create didn’t return an idReturn at least { id: "..." } from every create
INTERNAL_ERROR500Unexpected server error - and the code for a record that fails a factory’s inputSchema, surfacing as Invalid input for "<Model>"Check the failing model’s schema against the values the recipe sends, then your factory bodies and server logs

Other common problems

These surface as database or validation failures rather than as a distinct code - a dry run reports them with the message your own handler produced.

A failed dry-run card in Autonoma, bordered red. The heading reads "Dry run failed during up" and the body carries the error verbatim: SDK returned HTTP 500 - null value in column organization_id of relation account violates not-null constraint. Below the message sits a "Fix with coding agent" button, which opens instructions for connecting the Autonoma MCP so an agent can read the recipe and repair the handler

The message is passed straight through from your endpoint, so what you debug is your own stack trace, not a translation of it.

ProblemCauseFix
FK violation on upA required foreign key is missingSet every FK (including the scope field) explicitly as a { "_ref": "alias" }
cycle detected in _alias/_ref graphTwo records reference each other through _alias / _refBreak the cycle - the SDK rejects it rather than resolving it. Create one record first and attach the second reference from inside a factory
Parallel tests collideSame email/slug across runsPut a {{testRunId}} / {{testRunShortId}} token in every unique field
Link copied