JuliusBrussee/caveman · error
device login failed: server did not provide a delivery…
Error message
device login failed: server did not provide a delivery acknowledgement token
What it means
If the token response produced a durable grant (refresh token, gateway key material, or project_id) but no delivery_ack_token, the CLI throws before acknowledging. The acknowledgement proves to the control plane that the CLI stored the credential; acknowledging an undiscoverable credential would be unsafe, so the flow stops. Note the credentials are already saved locally before this check.
Solutions
- Upgrade the private instance's authorization server to a version that issues delivery_ack_token for durable grants
- Re-run login to get a complete token bundle
- If the grant should be ephemeral, reconfigure the server to stop issuing refresh tokens/gateway keys for this client
- Check instance logs for why the token response was incomplete
Example fix
// before
{ "refresh_token": "...", "project_id": "..." } // no delivery_ack_token
// after
{ "refresh_token": "...", "project_id": "...", "delivery_ack_token": "..." } Defensive patterns
Strategy: validation
Validate before calling
const durable = !!(tok.refresh_token || tok.gateway_api_key || tok.gateway_key_id || tok.project_id);
if (durable && (typeof tok.delivery_ack_token !== "string" || !tok.delivery_ack_token)) throw new Error("durable grant missing delivery_ack_token"); Type guard
function hasAckToken(tok) { return typeof tok?.delivery_ack_token === "string" && tok.delivery_ack_token.length > 0; } Try / catch
try { await login({ instance }) } catch (e) { if (e.message.includes("delivery acknowledgement token")) console.error("Server did not issue delivery_ack_token; upgrade the instance or re-login"); } Prevention
- Keep the instance's authorization server at a version that emits delivery_ack_token
- Re-login rather than reusing partial token bundles
- Alert on token responses lacking delivery_ack_token for durable grants
When it happens
Trigger: The token payload includes at least one of refresh_token, gateway_api_key, gateway_key_id, or project_id, but delivery_ack_token is missing, non-string, or empty.
Common situations: Authorization server version older than the CLI, not yet emitting delivery_ack_token; partial token response after a server-side error; misconfigured grant template on a private instance.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- device authorization failed: missing device code
- private device login requires a keyless project grant with…
- device authorization failed: HTTP
- device credential delivery acknowledgement failed
- device login failed
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/0750d5021f42e6bd.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:9761
...(typeof tok.gateway_key_id === "string" && tok.gateway_key_id ? { gateway_key_id: tok.gateway_key_id } : {}),
...(typeof tok.project_id === "string" && tok.project_id ? { project_id: tok.project_id } : {}),
};
const tokenStore = storeCredentials(credentials);
const organizationId = orgFromToken(accessToken);
const gateway = instance ? "" : resolveLoginGatewayUrl(baseURL, tok, code, argv);
const saved: Config = { baseURL, token: "", tokenStore };
if (organizationId) saved.organizationId = organizationId;
if (credentials.project_id) saved.projectId = credentials.project_id;
if (gateway) saved.gatewayUrl = gateway;
// Persist the complete local login state before the server-side receipt fence:
// an ACK may permanently purge the replay bundle, so a config write that fails
// must leave the grant retryable rather than acknowledging an undiscoverable
// credential.
await saveConfig(saved);
const durableGrant = Boolean(credentials.refresh_token || credentials.gateway_api_key || credentials.gateway_key_id || credentials.project_id);
const ackToken = typeof tok.delivery_ack_token === "string" ? tok.delivery_ack_token : "";
if (durableGrant) {
if (!ackToken) throw new Error("device login failed: server did not provide a delivery acknowledgement token");
// Do not print authenticated success or continue the post-login bridge
// until the control plane has recorded that this CLI stored the bundle.
await acknowledgeDeviceGrant(baseURL, credentials.access_token, code.device_code, ackToken);
}
if (instance) {
print({ authenticated: true, baseURL, organization_id: organizationId ?? null, project_id: credentials.project_id, scope: tok.scope, credential_kind: "none", token_store: tokenStore });
return;
}
// Mint/refresh the local-wrap entitlement for this device. Best
// effort: login never fails for seats or a down entitlement service.
await fetchAndStoreWrapEntitlement(baseURL, credentials.access_token);
if (gateway && wrapMode(gateway) === "managed") {
console.error(` ${mark("ok")} wrap now routes through the managed gateway (${gateway}) — governed reporting; verified stays zero without qualifying provider evidence`);
} else if (gateway) {
console.error(` ${mark("ok")} connected; wrap routes through ${gateway}`);
}
console.error(SYNC_DISCLOSURE);
print({ authenticated: true, baseURL, gateway_url: gateway || null, organization_id: organizationId ?? null, token_store: tokenStore });View on GitHub (pinned to 3ee70a1026)