eyaltoledano/claude-task-master · error · AuthenticationError

POLL_FAILED

POLL_FAILED

Error message

errorData.message || `HTTP ${response.status}`

What it means

AuthenticationError thrown when the flow-status poll returns any non-2xx, non-404 status. It carries the server-provided error message when the body parses as JSON, otherwise the raw HTTP status, and terminates the polling loop for the authentication flow.

Source

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

					method: 'GET',
					headers: {
						'User-Agent': `TaskMasterCLI/${this.getCliVersion()}`
					}
				});

				if (!response.ok) {
					const errorData = (await response.json().catch(() => ({}))) as {
						message?: string;
					};

					if (response.status === 404) {
						throw new AuthenticationError(
							'Authentication flow expired or not found',
							'FLOW_NOT_FOUND'
						);
					}

					throw new AuthenticationError(
						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) {

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Read the message (server error text or HTTP status) and address the indicated cause server-side.
  2. On 429, increase the polling interval or reduce concurrent logins, then retry the flow.
  3. On 5xx, retry after a short wait or restart the authentication flow if the backend remains unhealthy.
  4. Check backend/gateway logs around the failure time to identify the upstream error.
  5. Confirm no auth middleware in front of /api/auth/cli/status is rejecting unauthenticated CLI requests.

Example fix

// before: aggressive polling
await oauth.pollForCompletion(flowId, 60000); // polls every ~1s -> 429 POLL_FAILED
// after: catch, inspect status, retry with backoff or restart
try {
  await oauth.pollForCompletion(flowId, 60000);
} catch (e) {
  if (e.code === 'POLL_FAILED' && e.message.includes('429')) {
    await new Promise(r => setTimeout(r, 5000));
    await oauth.pollForCompletion(flowId, 60000);
  }
}
Defensive patterns

Strategy: try-catch

Type guard

function isPollFailed(e: unknown): e is AuthenticationError {
  return e instanceof AuthenticationError && (e as any).code === 'POLL_FAILED';
}

Try / catch

try {
  await oauth.pollForCompletion(flowId, timeout);
} catch (e) {
  if (isPollFailed(e)) {
    if (/429/.test(e.message)) {
      await new Promise(r => setTimeout(r, 5000)); // back off on rate limit
    } else {
      console.error(`Poll failed: ${e.message} — check auth server health`);
    }
  }
}

Prevention

When it happens

Trigger: pollForCompletion receives response.ok === false with a status other than 404 — e.g. 401 from expired proxy credentials, 429 rate limiting from polling too aggressively, 500/502/503 from backend errors or a failing proxy.

Common situations: Long polling intervals too short hitting server rate limits; backend deployment or outage mid-login; gateway/ingress returning 502 during upstream restarts; auth service requiring a session/cookie the CLI doesn't send.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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