JuliusBrussee/caveman · error
device authorization failed: missing device code
Error message
device authorization failed: missing device code
What it means
After a successful (2xx) device-authorization response, the CLI requires the JSON body to contain a device_code, which is needed to poll the token endpoint. A 2xx response without device_code means the server answered but not with a valid RFC 8628 payload, so login cannot proceed.
Solutions
- Verify the --instance URL targets the actual authorization server, not a proxy or wrong service
- Inspect the raw response of the device/code endpoint (curl with -i) to see what is actually returned
- Confirm the identity provider supports the device authorization grant (RFC 8628)
- Check for captive portals or middleware rewriting responses
Example fix
// before
const code = await codeResp.json();
// after (server-side fix: return a proper device grant)
res.json({ device_code, user_code, verification_uri, verification_uri_complete, interval }); Defensive patterns
Strategy: type-guard
Validate before calling
const body = await resp.json();
if (typeof body.device_code !== "string" || !body.device_code) throw new Error("device code endpoint returned an invalid payload"); Type guard
function hasDeviceCode(c) { return c != null && typeof c.device_code === "string" && c.device_code.length > 0; } Try / catch
try { await login({ instance }) } catch (e) { if (e.message.includes("missing device code")) console.error("Instance did not return an RFC 8628 device grant; check proxy/IdP"); } Prevention
- Point --instance directly at the authorization server, not through rewriting proxies
- Confirm the IdP supports the device authorization grant
- Log raw endpoint responses when debugging instance setup
When it happens
Trigger: The device/code endpoint returns 200 with JSON that lacks a truthy device_code field — e.g. an error envelope with HTTP 200, a proxy returning an HTML/empty page as JSON, or a non-standard authorization server response shape.
Common situations: Reverse proxy or captive portal intercepting the request and returning 200 with unexpected content; identity provider returning an error object instead of a device grant; pointing --instance at the wrong service that returns 200 for any path.
Related errors
- device login failed: server did not provide a delivery…
- 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/a3db8d535b8db7ab.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/index.ts:9683
function blockCloudLoginWhileBeta(): void {
throw new Error("Caveman Cloud platform is still in beta.");
}
async function login(argv: string[] = []) {
if (!argv.some((arg) => arg === "--instance" || arg.startsWith("--instance="))) blockCloudLoginWhileBeta();
const { noBrowser, instance } = validateLoginArgs(argv);
const baseURL = instance ?? resolveLoginBaseUrl(argv);
const codeResp = await fetch(`${baseURL}/api/v1/auth/device/code`, {
method: "POST",
redirect: "error",
headers: { "content-type": "application/json" },
body: "{}",
signal: AbortSignal.timeout(5000),
});
if (!codeResp.ok) throw new Error(`device authorization failed: HTTP ${codeResp.status}`);
const code = await codeResp.json();
if (!code.device_code) throw new Error("device authorization failed: missing device code");
const verificationURL = instance ? privateVerificationURL(code, instance) : code.verification_uri_complete ?? code.verification_uri;
console.error(`\n Authorize this device in your browser:`);
console.error(` ${verificationURL}`);
console.error(` code: ${code.user_code}\n`);
if (typeof verificationURL === "string" && shouldOpenLoginBrowser(noBrowser)) openLoginBrowser(verificationURL);
let intervalMs = Math.max(0, Number(code.interval ?? 5)) * 1000;
const deadline = Date.now() + Number(code.expires_in ?? 600) * 1000;
while (Date.now() < deadline) {
let tok: Record<string, unknown>;
let tokenStatus = 0;
let retryAfterMs = 0;
try {
const tokResp = await fetch(`${baseURL}/api/v1/auth/device/token`, {
method: "POST",
redirect: "manual",
headers: { "content-type": "application/json" },View on GitHub (pinned to 3ee70a1026)