Startup and readiness¶
Five symptoms that appear before any model request succeeds: a caller asks a
documentation site that publishes no gateway, the process refuses to start, /health says
ok while nothing serves, /readyz answers 503, or a request from another
machine is refused at the transport. Each entry quotes the sentence the
product actually prints and names the repair. The error vocabulary itself is
in errors; the rest of the runbook is at
runbook.
The documentation site publishes a gateway only when its deployment declares one¶
The documentation site serves /docs and Brama's
download under /download, redirects /
to /docs, and sends every other path to its
gateway forwarder. Whoever deploys the site chooses whether it also publishes a
Brama gateway: setting BRAMA_GATEWAY_ORIGIN on the site's deployment to
one credential-free HTTPS origin publishes the gateway running there, and each
call is forwarded to it with its method, path, query, headers and body. With
Stado, that origin is a public origin declared for the gateway with
stado web origin declare, the origin of the URL
stado web origin url /v1 prints.
Publication is off by default. A deployment that sets no origin publishes no
API, and every path outside /docs and /download, /health and /readyz
included, answers 404 with this body, the site, method and path filled in:
{"error":{"message":"<site> publishes no Brama gateway: its deployment sets no BRAMA_GATEWAY_ORIGIN, so POST /v1/chat/completions is not served here. Call the gateway your deployment runs, at the address it declares (with Stado: stado service directory connect brama). A deployment publishes its gateway on this site by setting BRAMA_GATEWAY_ORIGIN to that gateway's HTTPS origin. See /docs/runbook/startup-and-readiness#public-address",
"type":"request_error","code":"api_not_published","retryable":false}}
The caller was configured with a site that publishes no gateway. Point it at the address of the gateway its deployment runs; a deployment placed by Stado gives each machine its own route:
stado service directory connect brama
A value that is not one credential-free HTTPS origin answers 500 with code
gateway_origin_invalid, naming the value; an origin the forwarder cannot
reach answers 502 gateway_unreachable with the transport error.
Readiness is read from the gateway itself, as the entries below describe.
brama serve refuses to start¶
The sentence, verbatim (exit 1):
Server error: BRAMA_MODEL_ALIASES is required and is assembled by
src/release/bin/start-with-skarbiec from the sealed policy directory. Starting the
binary directly cannot obtain it: launch the gateway through that launcher, or
export the variable yourself. Restarting an unlaunched process will not
repair this.
The refusal names its own repair: managed configuration is generated by the
launcher, and restarting the same bare invocation cannot change the answer.
Start through src/release/bin/start-with-skarbiec; a standalone desktop
deployment instead passes --local-credentials-stdin
(configuration). A service host without Skarbiec
sets BRAMA_LOCAL_CREDENTIALS_FILE (in the environment or in
~/.config/brama/service.env) to an owner-only provider-to-credential
JSON file; the launcher then starts that standalone mode itself, says
starting Brama without Skarbiec: provider credentials from <file>
on stderr, and refuses a file that is not a regular, owner-only file. Other startup refusals in the same
class — duplicate client tokens, malformed identities, an alias route with
* or stray whitespace — also stop the process before it binds; the log
names the offending entry.
An alias declares exactly one route, so a startup refusal about a route is a
statement about that one destination. If the registry document itself is the
thing being refused, repair it with brama routes migrate
(cli/routes/migrate) and see
routes and ledger.
/health is ok but nothing works¶
That is /health doing its job, not a contradiction: its body says
"dependencies": "not_probed", and it answers ok from a gateway
whose every credential redemption is being refused. The only readiness
evidence is /readyz
(architecture). Point deploy
checks and uptime monitors at /readyz; treat a monitor on /health
as a monitor of the process, nothing more.
/healthz is the same process-only check as /health.
Neither waits for subscription inventory, credential redemption or provider model
discovery. A healthy response does not establish that any route can serve.
A route has no live subscription
A request does not join subscription or model discovery. It reads the last
completed background observation. If none has completed, it refuses with
route <r>: no live subscription; discovery failed: <cause>,
naming the operation still pending. If discovery failed, the refusal retains
the failed operation and its reported cause, including a vault that cannot be
opened. An empty trusted subscription catalog does not erase that failure.
Restore the named dependency before replaying the request. Later traffic starts another background observation while the previous failure remains visible; concurrent requests do not each start their own discovery. A failed discovery is not a provider generation timeout, and an already dispatched generation still follows the provider transport contract.
brama test --model <route> --agent-id <agent>
--allow-provider-cost --json is an explicit live diagnostic: it discovers
inventory before dispatch, and the best selector also discovers
models. It may contact a provider and incur cost. Unlike service admission,
this diagnostic waits for the discovery operation it was asked to perform.
/readyz answers 503¶
A readiness probe for one subscription reads that member's recorded credential and quota refusal before requesting its grant. Its diagnostic names the selected subscription and the retained cause, including the recorded quota reopening time when present. It does not claim that every other account failed because this member is unavailable, and a refused credential is not redeemed merely to repeat its recorded refusal.
reason retains the observed readiness problem. Inspect the corresponding fields rather than inferring account health from the HTTP status alone:
reason |
Meaning | Check |
|---|---|---|
no provider capability is configured |
zero direct providers — the gateway can route nothing on its own account | launcher policy: required_provider_capabilities and the authority-owned capability routes table |
a configured provider credential could not be obtained; the authorization chain is broken, not busy |
a capability or read grant refused just now | denied[] names the providers; check broker socket, workload registry, proof key (concepts/capability) |
an active subscription's credential did not redeem just now, so the next request that needs it will be refused whatever the catalogue lists |
a subscription is listed but its credential does not redeem | unredeemable[], then brama subscription list for the refusal sentence |
traffic can be served, but the vault holds a subscription account with incomplete routing metadata |
an account lacks routing identity metadata; brama:agent: is provenance, not a shared-pool routing gate |
unroutable_accounts[] identifies the actual missing brama:subscription, brama:provider: or brama:id: metadata |
every credential was obtained, and at least one active subscription contributes no model: it cannot be routed to |
a redeemable account whose provider offers it no discoverable model | unroutable[]; check provider model discovery and the account's plan |
Readiness returns inventory_errors entries with operation and detail when the account census, boot-catalog comparison, standalone provider inventory or direct credential acquisition fails. local_provider_names identifies a failed standalone map read; provider_credential includes the affected provider and original redemption cause. Direct-provider rows also retain that refusal in reason. Installing standalone credentials fixes that backend for the process lifetime: a poisoned credential map does not switch discovery or final-use redemption to managed storage. An empty account/provider list is not a complete census when these errors are present. The response sets degraded:true and operator_action_required:true, and includes the causes in the overall reason. An otherwise working route remains ready:true; inventory diagnostics do not disable it. Desktop's Posture screen displays the same warning even while the gateway can serve traffic.
Qualify the actual endpoint with cargo test --test readiness-inventory -- --ignored --nocapture. Supply TEST_SOURCE_REVISION matching the qualification binary's embedded source revision, BRAMA_READINESS_URL, GATEWAY_SOURCE_REVISION, EXPECTED_READY, EXPECTED_READINESS_HTTP_STATUS, and EXPECTED_INVENTORY_ERROR naming an observed cause. The test refuses a mismatched qualification binary before contacting the gateway; the serving revision is checked independently. A refused census also requires its EXPECTED_INVENTORY_OPERATION. Use a real isolated gateway with the relevant unreadable vault, malformed boot catalog, unavailable standalone map or refused direct credential. A direct credential fixture additionally supplies EXPECTED_INVENTORY_PROVIDER and must expose the same cause in that provider's readiness row. The journey does not manufacture a provider, poison a lock, edit a deployment or restart it. For the healthy completed census, supply an empty expected error. Reports retain the test build, request, HTTP status, full returned body or actual transport/body-read failure, and serving revision under target/real-tests/readiness-inventory. This API journey does not qualify the native screen; inspect the same actual report in Posture separately.
configured_provider_capabilities identifies an incomplete provider inventory in both interim and final readiness reports. Its detail preserves the declared grant-route file and actual filesystem, JSON or object-shape failure, or the standalone-map or subscription-classification refusal. Qualify the final report with EXPECTED_INVENTORY_OPERATION=configured_provider_capabilities and the independently observed cause using the same readiness journey. A failed inventory read is never a successful empty provider pool. Adoption preview refuses the same failure before importing configuration; the administrative snapshot, process stats and authenticated deployment catalogue return 503 with that cause when they cannot construct their inventory.
configured_request_sign_agents in inventory_errors means the signing-agent declaration could not be read or decoded; it does not mean no agents were configured. The final readiness reason preserves that cause and Desktop Posture displays the same inventory warning. Use the readiness journey with this operation and the independently observed declaration error. Maintenance exposes the same failure in plan_usage.failed with operation and error rather than reporting a successful empty sweep. A working direct provider remains independently serviceable.
Waiting repairs none of these — every 503 here is an authorization or inventory statement, not load. The three subscription-shaped rows are worked through in credentials and subscriptions.
Requests from another machine answer 426¶
{"error":{"code":"secure_transport_required",
"message":"HTTPS is required except for direct loopback requests", ...}}
The transport guard accepts loopback, the gateway's own bound address, peers
in BRAMA_ENCRYPTED_PEER_IPS, and proxies in
BRAMA_TRUSTED_PROXY_IPS whose forwarded headers state https —
nothing else, and forwarded headers from an unlisted peer are never trusted (a
forged X-Forwarded-Proto: https changes nothing; captured). Repair: front
the gateway with the approved TLS terminator and list that terminator's peer
IP, or call over the mesh hop that is already encrypted.