eyaltoledano/claude-task-master · error · AuthenticationError

MISSING_TOKENS

MISSING_TOKENS

Error message

'Server returned no encrypted tokens'

What it means

MISSING_TOKENS is thrown when the poll reports status 'complete' but the response body lacks the `encrypted_tokens` field. The CLI decrypts tokens locally with an ephemeral keypair, so a 'complete' result without the encrypted payload is a server-side contract violation and cannot be recovered.

Source

Thrown at packages/tm-core/src/modules/auth/services/oauth-service.ts:364

						errorData.message || `HTTP ${response.status}`,
						'POLL_FAILED'
					);
				}

				const data = (await response.json()) as FlowStatusResponse;

				if (!data.success) {
					throw new AuthenticationError(
						data.message || 'Failed to check status',
						'POLL_FAILED'
					);
				}

				switch (data.status) {
					case 'complete': {
						// Decrypt tokens using our private key
						if (!data.encrypted_tokens) {
							throw new AuthenticationError(
								'Server returned no encrypted tokens',
								'MISSING_TOKENS'
							);
						}

						const tokens = decryptTokens(
							data.encrypted_tokens,
							this.keyPair.privateKey
						);

						this.logger.debug('Successfully decrypted authentication tokens');

						return {
							token: tokens.access_token,
							refreshToken: tokens.refresh_token,
							userId: tokens.user_id,
							email: tokens.email,
							expiresAt: tokens.expires_in

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Retry `credentials()` to start a fresh flow with a new keypair — a transient server glitch is the most common cause.
  2. Check that CLI and backend versions match (the status response schema may have changed); update @tm/core / the CLI.
  3. Verify no proxy/middleware strips or truncates the response body (encrypted_tokens can be large).
  4. Report persistent occurrences with the flow_id to the backend team — 'complete' without tokens is a server bug.

Example fix

// before: assumes complete always carries tokens, hard failure
const creds = await oauthService.credentials();
// after: handle MISSING_TOKENS with one retry
try {
  return await oauthService.credentials();
} catch (e) {
  if (e instanceof AuthenticationError && e.code === 'MISSING_TOKENS') {
    return oauthService.credentials(); // fresh flow regenerates keypair
  }
  throw e;
}
Defensive patterns

Strategy: retry

Type guard

function isCompleteWithTokens(d: FlowStatusResponse):
  d is FlowStatusResponse & { status: 'complete'; encrypted_tokens: string } {
  return d.status === 'complete' && typeof d.encrypted_tokens === 'string' && d.encrypted_tokens.length > 0;
}

Try / catch

try {
  return await oauthService.credentials();
} catch (e) {
  if (e instanceof AuthenticationError && e.code === 'MISSING_TOKENS') {
    // fresh flow regenerates keypair and asks server for tokens again
    return oauthService.credentials();
  }
  throw e;
}

Prevention

When it happens

Trigger: `credentials()` polling receives `{success:true,status:'complete'}` but `data.encrypted_tokens` is undefined/null — the backend marked the flow complete without attaching the RSA-encrypted token payload.

Common situations: Backend version mismatch where the status endpoint no longer includes encrypted_tokens; a reverse proxy or response-transforming middleware stripping large fields; server bug when storing flow results; client pointed at an older API deployment.

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/147f033f7cb3bcfe. Report an issue: GitHub.