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

  1. Upgrade the private instance's authorization server to a version that issues delivery_ack_token for durable grants
  2. Re-run login to get a complete token bundle
  3. If the grant should be ephemeral, reconfigure the server to stop issuing refresh tokens/gateway keys for this client
  4. 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

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


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)