Skip to content

Error codes

The broker refuses a request with an HTTP status and a JSON body {"code": "…", "error": "…"}. agent-secrets prints a refusal as <error> (<code>). A message shown as an error’s own text may arrive wrapped in more detail; (varies) marks a message built at run time.

Code Status Message Where
ACCOUNT_LACKS_POWER 403 the caller … may not call … POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
every Caller ServiceAccount token route
ACCOUNT_NOT_LISTED 403 this ServiceAccount does not log in as this service
this ServiceAccount is not in BROKER_SERVICE_LOGINS
this account is not in BROKER_API_ACCOUNTS
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/launcher-credentials/token
every Caller ServiceAccount token route
every Service login ServiceAccount token route
ACCOUNT_TOKENS_OFF 401 this broker trusts no Kubernetes token issuer, so no service authenticates with a ServiceAccount token
this broker trusts no token issuer for its API callers, so no caller authenticates with an identity token
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
every Caller ServiceAccount token route
every Service login ServiceAccount token route
ACCOUNT_TOKEN_EXPIRED 401 the ServiceAccount token has expired
the caller’s identity token has expired
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
every Caller ServiceAccount token route
every Service login ServiceAccount token route
ACCOUNT_TOKEN_INVALID 401 the Google identity token names no verified account, so it names no caller (ask for it with format=full)
the ServiceAccount token does not verify
the caller’s identity token does not verify
the caller’s token names no issuer this broker trusts for its API callers
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
every Caller ServiceAccount token route
every Service login ServiceAccount token route
ACCOUNT_TOKEN_TOO_LONG_LIVED 401 the ServiceAccount token lives longer than an hour from its issue
the caller’s identity token lives longer than an hour from its issue
the caller’s identity token names no issue time (iat)
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
every Caller ServiceAccount token route
every Service login ServiceAccount token route
ALREADY_ENROLLED 409 this runtime is already enrolled and live POST /v1/enrollments
APPROVER_REQUIRED 400 approver is required GET /v1/grants
GET /v1/launcher-credentials
GET /v1/pending
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/grants/{id}/revoke-by-approver
POST /v1/launcher-credentials/{id}/revoke-by-approver
CODE_MISMATCH 403 confirmation code does not match POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
CODE_REQUIRED 400 code is required
code is required to decide a machine login
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/machine-logins/lookup
CREDENTIAL_ID_INPUT 400 launcher credential ids are UUIDs POST /v1/launcher-credentials/{id}/revoke-by-approver
POST /v1/operator/machines/{id}/retire
POST /v1/operator/machines/{id}/revoke
DATABASE_UNAVAILABLE 503 introspect token failed: a dependency the broker needs is unavailable
ping Postgres failed: a dependency the broker needs is unavailable
read launcher credential failed: a dependency the broker needs is unavailable
read the sign-in status failed: a dependency the broker needs is unavailable
verify launcher proof failed: a dependency the broker needs is unavailable
verify proof failed: a dependency the broker needs is unavailable
GET /healthz
GET /signin/status
POST /v1/oauth/introspect
every Machine credential route
every Renewal session proof route
every Session proof route
DECIDE_ON_BROKER_PAGE 403 a secret request is decided only on the secrets broker’s own page, by a person signed in to the broker: … POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
ENROLLMENT_ID_INPUT 400 enrollment ids are UUIDs DELETE /v1/enrollments/{id}
POST /v1/enrollments/{id}/renew
ENROLLMENT_NOT_LIVE 401 enrollment is not live
the machine login that enrolled this session has ended
POST /v1/enrollments/{id}/renew
every Renewal session proof route
GRANT_CHAIN_INVALID 403 this grant’s approval chain no longer verifies POST /v1/grants/{id}/values
GRANT_ID_INPUT 400 grant ids are UUIDs POST /v1/grants/{id}/revoke-by-approver
POST /v1/grants/{id}/revoke
POST /v1/grants/{id}/values
POST /v1/operator/grants/{id}/revoke
GRANT_NOT_LIVE 403 grant is expired, revoked, or its session ended POST /v1/grants/{id}/values
GRANT_REQUIRES_LIFETIME 400 a requested secret requires a shorter grant lifetime POST /v1/requests
INTERNAL 500 cancel request failed
create enrollment failed
create request failed
decide machine login failed
list grants for approver failed
list launcher credentials failed
list pending requests failed
list person sign-ins failed
lookup machine login failed
read credential request failed
read credential request kind failed
read enrollment failed
read grant values failed
read live grants failed
read request failed
read request owner failed
read the grant log failed
register the pod’s session name failed
renew enrollment failed
reread secret failed
retire launcher credential failed
revoke enrollment failed
revoke grant failed
revoke launcher credential failed
revoke person sign-in failed
token login failed
DELETE /v1/enrollments/{id}
GET /v1/enrollments/self
GET /v1/grant-log
GET /v1/grants
GET /v1/launcher-credentials
GET /v1/operator/grants
GET /v1/operator/machines
GET /v1/pending
GET /v1/person-signins
GET /v1/requests/{id}
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/enrollments/{id}/renew
POST /v1/enrollments
POST /v1/grants/{id}/revoke-by-approver
POST /v1/grants/{id}/revoke
POST /v1/grants/{id}/values
POST /v1/launcher-credentials/token
POST /v1/launcher-credentials/{id}/revoke-by-approver
POST /v1/machine-logins/lookup
POST /v1/oauth/exchange/pod-sessions
POST /v1/operator/grants/{id}/revoke
POST /v1/operator/machines/{id}/retire
POST /v1/operator/machines/{id}/revoke
POST /v1/person-signins/{id}/revoke
POST /v1/requests/{id}/cancel
POST /v1/requests
POST /v1/secrets/{name}/reread
INVALID_DECISION 400 body must be one valid JSON object: (varies) POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
INVALID_ENROLLMENT 400 body must be one valid JSON object: (varies) POST /v1/enrollments
INVALID_KIND 400 kind must be “session” or “pod” POST /v1/enrollments
INVALID_LOOKUP 400 body must be one valid JSON object: (varies) POST /v1/machine-logins/lookup
INVALID_NARROWING 400 body must be one valid JSON object: (varies)
github_app.… …
POST /v1/grants/{id}/values
INVALID_RENEWAL 400 body must be one valid JSON object: (varies) POST /v1/enrollments/{id}/renew
INVALID_REQUEST 400 body must be one valid JSON object: (varies)
the form must parse and be at most … bytes
POST /v1/launcher-credentials/token
POST /v1/oauth/exchange/pod-sessions
POST /v1/oauth/introspect
POST /v1/requests
INVALID_REVOKE 400 body must be one valid JSON object: (varies) POST /v1/grants/{id}/revoke-by-approver
POST /v1/launcher-credentials/{id}/revoke-by-approver
POST /v1/person-signins/{id}/revoke
INVALID_SLOT 400 a slot is only for a pod enrollment and must match ^[a-z][a-z0-9-]{0,62}$ POST /v1/enrollments
KEY_HOLDS_LIVE_CREDENTIAL 409 this machine login’s key already holds a live launcher credential POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/launcher-credentials/token
LAUNCHER_INVALID 401 the launcher credential is not valid
this route needs a launcher proof, not a session proof
POST /v1/enrollments
every Machine credential route
MINT_FAILED 502 the broker could not mint a token from this secret POST /v1/grants/{id}/values
MIXED_APPROVERS 400 the requested secrets need different approvers; request them separately POST /v1/requests
NARROWING_BEHIND_AIRLOCK 409 this grant holds a name behind the airlock, which takes no narrowing POST /v1/grants/{id}/values
NARROWING_NOT_APPLICABLE 400 this grant holds no github-app secret to narrow POST /v1/grants/{id}/values
NARROWING_OWNER_NOT_LISTED 403 the narrowing names an account a github-app secret of this grant does not serve POST /v1/grants/{id}/values
NARROWING_REFUSED 422 the narrowing cannot be served POST /v1/grants/{id}/values
NOT_APPROVER 403 only the grant’s approver or its enrollment’s operator may revoke it
only the person who approved a person’s machine login may revoke it
only the record’s approver may decide it
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/grants/{id}/revoke-by-approver
POST /v1/launcher-credentials/{id}/revoke-by-approver
POST /v1/operator/grants/{id}/revoke
POST /v1/operator/machines/{id}/revoke
NOT_CALLING_CREDENTIAL 403 a machine login retires only itself: sign with the credential the path names POST /v1/operator/machines/{id}/retire
NOT_ENROLLING_CREDENTIAL 403 only the machine login that made an enrollment carrying no operator may end it DELETE /v1/enrollments/{id}
NOT_FOUND 404 no sign-in of that person has that id
no such credential request
no such grant
no such machine login
no such request
GET /v1/requests/{id}
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/grants/{id}/revoke-by-approver
POST /v1/grants/{id}/revoke
POST /v1/launcher-credentials/{id}/revoke-by-approver
POST /v1/operator/grants/{id}/revoke
POST /v1/operator/machines/{id}/revoke
POST /v1/person-signins/{id}/revoke
POST /v1/requests/{id}/cancel
NOT_YOURS 403 a session may only renew its own enrollment
this request belongs to another session
this request or grant belongs to another session
GET /v1/requests/{id}
POST /v1/enrollments/{id}/renew
POST /v1/grants/{id}/revoke
POST /v1/grants/{id}/values
POST /v1/requests/{id}/cancel
NO_SUCH_CODE 404 no pending machine login has this code POST /v1/machine-logins/lookup
OPERATOR_MISMATCH 403 this launcher credential enrols a different operator DELETE /v1/enrollments/{id}
POST /v1/enrollments
PAGE_INVALID 400 after is not a whole number of zero or more
limit is not a whole number of zero or more
GET /v1/grant-log
PERIOD_INVALID 400 since is not an RFC 3339 time, such as 2026-01-01T00:00:00Z
until is not an RFC 3339 time, such as 2026-01-01T00:00:00Z
GET /v1/grant-log
PERIOD_NOT_CLOSED 400 until must be at least an hour before now, so that every row of the period has committed before the review reads it GET /v1/grant-log
PERIOD_REQUIRED 400 since is required: an RFC 3339 time, such as 2026-01-01T00:00:00Z
until is required: an RFC 3339 time, such as 2026-01-01T00:00:00Z
GET /v1/grant-log
PERSON_REQUIRED 400 person is required GET /v1/person-signins
POST /v1/person-signins/{id}/revoke
POD_ACCOUNT_NOT_LISTED 403 exchange: no entry lists this identity POST /v1/oauth/exchange/pod-sessions
POD_CALLER_IS_THE_POD 403 this is the caller’s own pod, … of …, and a registrar registers a pod other than the one it runs in POST /v1/oauth/exchange/pod-sessions
POD_IDENTITY_MISMATCH 403 the projected token does not identify this pod POST /v1/enrollments/{id}/renew
POST /v1/enrollments
POD_NOT_BOUND 400 exchange: the subject token is bound to no pod POST /v1/oauth/exchange/pod-sessions
POD_NOT_LAUNCHED 403 this machine login does not launch the pods of that service account POST /v1/enrollments
POD_SELF_ENROLL_NO_SESSION 403 a pod enrolling itself states no session name POST /v1/enrollments
POD_SELF_ENROLL_ONLY 403 a pod’s own machine login enrols that pod alone POST /v1/enrollments
POD_TOKEN_EXPIRED 401, 403 the pod’s ServiceAccount token has expired
the projected token has expired
POST /v1/enrollments/{id}/renew
POST /v1/enrollments
POST /v1/oauth/exchange/pod-sessions
POD_TOKEN_INVALID 401 the pod’s ServiceAccount token does not verify POST /v1/oauth/exchange/pod-sessions
POD_TOKEN_REQUIRED 403 a pod enrollment’s renewal must carry its projected token POST /v1/enrollments/{id}/renew
PROOF_INVALID 401 enrollment is not live
proof invalid
proof invalid: not live
this route needs a session proof, not a launcher proof
GET /v1/enrollments/self
POST /v1/requests
every Renewal session proof route
every Session proof route
RATE_LIMITED 429 too many launcher credential requests; try again later
too many requests from this address; try again later
too many requests with a ServiceAccount token; try again later
too many secret rereads; try again later
too many token logins for this ServiceAccount; try again later
GET /signin/status
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/launcher-credentials/token
POST /v1/secrets/{name}/reread
every Caller ServiceAccount token route
every Service login ServiceAccount token route
RECORD_ID_INPUT 400 record ids are lowercase-hex sha256 hashes POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
RECORD_TERMINAL 409 this machine login expired before its approver acted on it
this machine login has already been decided
POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
REQUEST_ENDED 503 the request ended before the reread finished; send it again POST /v1/secrets/{name}/reread
REQUEST_ID_INPUT 400 request ids are UUIDs GET /v1/requests/{id}
POST /v1/requests/{id}/cancel
REQUEST_INVALID 400 request object invalid POST /v1/launcher-credentials/token
POST /v1/requests
REQUEST_PENDING 409 a request for one or more of these secrets is already pending POST /v1/requests
REQUEST_TERMINAL 409 request is already decided POST /v1/requests/{id}/cancel
REQUEST_TOO_LARGE 413 request body exceeds … bytes POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
POST /v1/enrollments/{id}/renew
POST /v1/enrollments
POST /v1/grants/{id}/revoke-by-approver
POST /v1/grants/{id}/values
POST /v1/launcher-credentials/token
POST /v1/launcher-credentials/{id}/revoke-by-approver
POST /v1/machine-logins/lookup
POST /v1/oauth/exchange/pod-sessions
POST /v1/person-signins/{id}/revoke
POST /v1/requests
SECRET_NAME_INVALID 400 not an agent secret name POST /v1/secrets/{name}/reread
SECRET_NOT_IN_STORE 404 secret is not in the secrets store POST /v1/grants/{id}/values
SERVICE_CREDENTIAL 403 a service’s machine login has no operator; machine and grant commands are a person’s GET /v1/operator/grants
GET /v1/operator/machines
POST /v1/operator/grants/{id}/revoke
POST /v1/operator/machines/{id}/revoke
SERVICE_LOGS_IN_WITH_TOKEN 400 a service logs in with its own projected Kubernetes ServiceAccount token at POST /v1/launcher-credentials/token, never through a code a person approves POST /v1/credential-requests/{record}/approve
POST /v1/credential-requests/{record}/deny
SESSION_FIXED 409 exchange: the entry fixes the session name it writes under POST /v1/oauth/exchange/pod-sessions
SESSION_HELD 403 another identity holds this session name POST /v1/enrollments
SESSION_ID_INPUT 400 session id must be at most 128 characters with no whitespace or control character POST /v1/requests
SESSION_INVALID 400 exchange: the request names an unusable session POST /v1/oauth/exchange/pod-sessions
SHUTTING_DOWN 503 the broker is shutting down and is no longer taking new traffic GET /healthz
SIGNIN_ID_INPUT 400 sign-in ids are UUIDs POST /v1/person-signins/{id}/revoke
TOKEN_EXPIRED 401 the ServiceAccount token has expired POST /v1/launcher-credentials/token
TOKEN_INVALID 401 the ServiceAccount token does not verify POST /v1/launcher-credentials/token
TOKEN_LOGIN_OFF 404 this broker trusts no Kubernetes token issuer, so no service logs in with a token POST /v1/launcher-credentials/token
TOKEN_REQUIRED 400 token is required POST /v1/oauth/introspect
TOKEN_TOO_LONG_LIVED 401 the ServiceAccount token lives longer than an hour from its issue POST /v1/launcher-credentials/token
UNKNOWN_SECRET 400 no agent secret has this name POST /v1/requests

agent-secrets-helper answers a request it refuses with one of these codes and an error message; agent-secrets prints them as <code>: <error>.

Code Meaning
BAD_REQUEST Answers a request that is not one JSON object per line, names an unknown op, leaves out a field its op needs, or asks sign-launcher for anything but one of the four operator routes under this helper’s broker.
DRAINING Answers register and enroll-session-key once drain found no sessions: the helper is about to be restarted, and the caller should retry against the new one.
ENROLL_FAILED Answers an enroll-session-key the broker refused or could not be asked; the error says why.
IN_SESSION Answers sign-launcher from a process inside a registered session’s process tree, or one whose ancestry the helper cannot follow to init (a parent it cannot read, a loop, or past 64 processes), so a session’s own commands cannot act as its operator. A process that leaves its session’s tree (a double fork or setsid, reparented to init or a subreaper) is not refused, and the operator’s user can stop the helper anyway: it guards a session’s own process tree, not a boundary against code running as that user.
KEYGEN Answers a register the helper could not make the new session’s signing key for; the error says why.
LOGIN_FAILED Answers a login the helper could not start with the broker; the error says why.
NOT_A_SESSION Answers sign, sign-request or unregister from a process that descends from no session agent-secrets register registered.
NOT_ENROLLED Answers sign or sign-request for a registered session that is still enrolling: the helper holds a launcher credential, and its enroll loop has not succeeded yet.
NO_CREDENTIAL Answers sign, sign-request or sign-launcher while the helper holds no launcher credential: the machine was never logged in, its machine file is gone, or the broker refused its login (revoked, lapsed, or a reused refresh token), until the operator logs the machine in. A restart resumes a kept login, so it alone does not cause this. The helper then enrolls no one, so a session has no broker identity, and the operator’s shell has no machine login to act as. A register reply for such a session carries it too, beside OK.
PEER_UNIDENTIFIED Answers a caller the kernel could not identify, or one whose process exited or changed while the helper was identifying it.
SIGN Answers sign, sign-request or sign-launcher when signing the proof or the request object failed; the error says why.
UNENROLL_FAILED Answers an unenroll-session-key the broker refused or could not be asked; the error says why.

agent-secrets exits 0 when it is done and 1 when it failed; these are the other codes it exits with.

Exit code Meaning
2 Usage error: a flag, argument, token file, or required environment value is invalid
75 Request still waiting for a person to approve it
76 Renew reached a refusal in terminalRenewal; the worker shim must not restart it
77 Request denied
126 Register –exec command exists but could not run
127 Register –exec command was not found
129 Secret prompt received SIGHUP
130 Secret prompt received SIGINT
131 Secret prompt received SIGQUIT
143 Secret prompt received SIGTERM