Automation failure modes

Start with the HTTP status and code, then check the command result if the request was accepted. Coded API errors contain code; validation errors can also contain field_errors. Some refusals include gate and missing, but those fields are not present on every error. See service tokens for setup and Ansible for connection options.

401 during login with an old CLI

A CLI older than v1.7.4 can accept an alpst- key at login and then fail to verify the user profile. The request returns 401 auth_token_missing, and the old CLI prints:

Login succeeded but failed to verify user profile: request denied by server. Please try logging in again.

Use Alpacon CLI v1.7.4 or later and check the version inside the job’s container or runner. Pass the key with alpacon login ... -t "$ALPACON_SERVICE_TOKEN". The CLI does not read ALPACON_URL or ALPACON_TOKEN; those environment variables configure the Ansible connection.

202 while a token waits for approval

Creating a service token returns 202 when approval is required. The response includes key, status: "pending_approval", risk_level, risk_details (entries with scope, reason, and level), and approval_request_id. A key returned here is not ready to use: it returns 401 auth_authentication_failed until approval.

Only low-risk scopes requested in the web console by an account with the admin role activate immediately. Command and file-transfer scopes always wait. Have a Superuser or an approver for the request approve it in the web console. Check GET /api/auth/service-tokens/tokens/{id}/ for activation_state: "active" and enabled: true before starting the job.

A security change also returns 202 with status, risk_level, risk_details, and approval_request_id, but no key. The old settings remain in force until approval. A second pending change returns 400 service_token_update_pending; finish or cancel the existing request first.

A command waiting for a person has status: "awaiting_approval" on its command record; this is different from a token-creation 202. Review the existing command in the web console.

403 with missing permissions

A token missing a scope can receive:

json
{
  "code": "api_token_scope_missing",
  "gate": "token_scope",
  "missing": "scope:command:create"
}

missing can be one string or a list. It can name scopes or requirements such as role, command_preapproval, approval, presence, work_session, plan, approved_account, other_approver, or allowed_agent. For the example above, the CLI prints permission denied: missing scope scope:command:create.

Check that both the application’s global role and the token allow the operation. Request the needed token-scope change and wait for approval. A role refusal uses rbac_permission_required or rbac_object_permission_required, gate: "role", and missing: "role"; the CLI prints permission denied: missing role. Ask an administrator to review the role assignment. Adding a scope does not satisfy an account, approval, or presence requirement.

429 and Retry-After

A service token over its request limit receives 429 with:

json
{"code": "api_rate_limited", "gate": "rate"}

The Retry-After header gives the number of seconds to wait. Limits apply per token; the default is 1000/hour when no rate is configured. Wait at least that long before retrying and reduce concurrent polling or job requests. A change to the token’s rate limit needs approval.

The CLI prints too many requests—please try again later and backs off in its polling loops. Ansible raises the HTTP 429 error immediately, so arrange the retry in the job. A monthly plan cap returns 402, not 429, and also includes Retry-After.

Sudo refused

On Alpacon Cloud, service-token sudo is allowed below Critical, including unassessed commands, and refused at Critical unless the workspace is Advisory. In Advisory, it is not refused for risk at any level, and the decision is recorded. Outside Advisory, a workspace token_exec rule can tighten the risk threshold. The workspace sudo setting must be on; otherwise sudo is refused with workspace_sudo_with_mfa_disabled. A risk refusal uses sudo_risk_denied. If the whole command is rejected before delivery, its status is rejected; read rejection_cause, rejection_gate, and rejected_at on command detail. Ansible returns rc: 1 with rejected on stderr. For a command that ran but failed at sudo, read its output and the Denied tab of Privilege elevation.

The CLI’s risk-denial hint is sudo was denied by runtime risk assessment; this command is not permitted in this work session. It uses that wording for token commands too. Review the refused operation and use a narrower command that the application is allowed to run.

On a default self-hosted installation, every service-token sudo is refused with sudo_command_not_authorized, regardless of risk. The CLI explains that the service token cannot be elevated on that deployment. Ansible uses only tokens, so become is unavailable on a default self-hosted installation. Sudo policies do not apply to service tokens, and retrying does not create a human sudo-approval request.

401 after a token expires or a key changes

An expired service token returns 401 with {"code": "auth_authentication_failed"} and WWW-Authenticate: Token. The same response covers invalid, disabled, pending, and deleted tokens, including tokens whose application was deleted. The response alone cannot distinguish them. The CLI prints authentication failed: please run 'alpacon login' again.

Check the token’s status and expiry in the web console. For an expired token, issue a replacement, complete its approval, and update the CI secret before retrying. If a key was rotated, replace the CI secret immediately: the old key stops as soon as rotation completes. Rotation resets expiry from the current time, using the rotation policy (90 days by default), so check the new date too. If the token was disabled, re-enabling needs approval; if it is pending, finish approval before retrying.

IP address or access time refused

401 auth_ip_not_allowed means the runner’s address is outside the token’s allowed IPs. 401 auth_access_outside_allowed_time means the request is outside the permitted hours or days, evaluated in UTC. The CLI prints request denied by server for these coded errors.

Check the runner’s outgoing IP and schedule against the token’s restrictions. Request a restriction change if the job needs different access; that change requires approval.

Credential verification unavailable

503 auth_verification_unavailable means the server could not verify the credential, rather than rejecting it. The CLI prints the server could not verify your credential right now—it was not rejected, so try again in a moment. Retry after a short delay.

400 for the server account

A service token can run only as an account owned by its application. Check the validation code and field_errors:

CodeCause and action
workspace_direct_root_disabledroot was requested while direct root is disabled. Use the application’s account.
application_system_user_not_foundNo bound account or provisionable application username was found. Bind the account, or set the application’s username and enable provisioning on a supported Linux server with a current agent.
system_user_bound_under_another_nameThe bound account uses another name. Use the bound account’s name.
server_username_groupname_invalidThe selected account does not belong to the application. Choose an application-owned account.
system_user_access_deniedThe account’s login is disabled or expired. Ask its administrator to review its status.

For Ansible, set ansible_user explicitly; its default of root cannot be used with a service token. ACL rules cannot grant ownership of another account.

Server not connected or commissioned

A request for one server returns 400 server_not_connected or 400 server_not_commissioned when the target is unavailable for commands. Restore the connection or commission the server before retrying. A request using servers can queue for disconnected targets, so check each command’s status instead of assuming that acceptance means execution.

Token scopes exceed the application’s role

Token creation returns 400 service_token_scope_exceeds_role when the requested scopes exceed the application’s global role. Have an authorized administrator assign the required global role, or reduce the scopes before requesting the token again. If a role is revoked later, tokens that exceed the remaining permissions are disabled; their next request returns 401.

Server, command, or file ACL refused

403 api_token_acl_not_allowed means an access rule does not allow the operation. It has no missing field. The CLI prints denied by token access control—this token may not perform that action; review its rules with 'alpacon token acl'.

For a service token, a single-server request can instead return 400 does_not_exist under field_errors.server when the server is outside its server ACL or does not exist. Check the server ID and add the server rule after the token is approved. For file transfers, allow the path and direction: upload, download, or both.

On Cloud, a command outside the pre-approved commands is accepted with 201, then ends rejected with rejection_cause command_acl_denied or command_acl_unavailable. Ansible reports Command was rejected by the approval policy for this too; it can mean a missing command rule. On self-hosted deployments, the command ACL refusal is 403 api_token_acl_not_allowed; check the ACL against the entire submitted line. On Cloud, ask a Command ACL admins member to manage Pre-approved commands on the service token’s page in the web console. API command-ACL writes return 405 command_acl_moved there; repeating the CLI hint’s write cannot fix it.

Inline credentials refused

400 command_inline_credential means the submitted command contains an inline credential. Remove the credential from the command line and supply it through the job’s secret handling before retrying.

Interactive operation refused

403 auth_interactive_channel_requires_presence means a token was used for an interactive operation such as Websh, a tunnel, or the browser editor. Use alpacon exec for a non-interactive command, or sign in with alpacon login without -t for interactive work.

Workspace suspended

Writes return 403 workspace_suspended while the workspace is suspended. Ask a workspace administrator to resolve the suspension before retrying the job.

Ansible configuration or file transfer fails

Missing ALPACON_URL or ALPACON_TOKEN produces an Ansible required-option error. Set the workspace URL and approved alpst- key. An ambiguous server name produces Multiple servers match name ...; set alpacon_server_id to the intended server UUID. File transfers require S3-backed storage; confirm that storage and the token’s file ACLs before retrying. See Ansible for the complete connection options.

Last updated: