{"record":{"id":"045fb9c23f7e5f9c","repo":"paperclipai/paperclip","slug":"cli-auth-challenge-was-cancelled","errorCode":null,"errorMessage":"CLI auth challenge was cancelled.","messagePattern":"CLI auth challenge was cancelled\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/client/board-auth.ts","lineNumber":278,"sourceCode":"            authorization: `Bearer ${challenge.boardApiToken}`,\n          },\n        },\n      );\n      setStoredBoardCredential({\n        apiBase,\n        token: challenge.boardApiToken,\n        userId: me.userId ?? me.user?.id ?? null,\n        storePath: params.storePath,\n      });\n      return {\n        token: challenge.boardApiToken,\n        approvalUrl,\n        userId: me.userId ?? me.user?.id ?? null,\n      };\n    }\n\n    if (status.status === \"cancelled\") {\n      throw new Error(\"CLI auth challenge was cancelled.\");\n    }\n    if (status.status === \"expired\") {\n      throw new Error(\"CLI auth challenge expired before approval.\");\n    }\n\n    await sleep(pollMs);\n  }\n\n  throw new Error(\"CLI auth challenge expired before approval.\");\n}\n\nexport async function revokeStoredBoardCredential(params: {\n  apiBase: string;\n  token: string;\n}): Promise<void> {\n  const apiBase = normalizeApiBase(params.apiBase);\n  await requestJson<{ revoked: boolean }>(`${apiBase}/api/cli-auth/revoke-current`, {\n    method: \"POST\",","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/client/board-auth.ts#L260-L296","documentation":"Thrown by loginBoardCli() when the polled challenge status is `cancelled`. The CLI created a cli-auth challenge, printed/approval-opened the URL, and while polling /api/cli-auth/{id}/status the server reported status === \"cancelled\" — meaning a board operator explicitly rejected the CLI login request, or it was cancelled server-side. This is an intentional terminal state, not a bug.","triggerScenarios":"A board user clicked \"Cancel\" / \"Deny\" on the approval page while the CLI was polling. Also possible if another session or an admin force-cancels the challenge by id. Distinguished from expiry ([2]/[3]) by the explicit cancelled status.","commonSituations":"User started `paperclipai login`, changed their mind, and denied it in the board UI. Multiple CLI sessions racing on the same approval page. A board admin revoking a pending login.","solutions":["Re-run `paperclipai login` to start a fresh challenge and approve it this time.","Confirm the approving board user actually has the permissions to approve CLI access for the requested company/instance.","If cancellations are unexpected, check server logs for who issued the cancel on the challenge id."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await loginBoardCli(params);\n} catch (err) {\n  if (err instanceof Error && err.message === 'CLI auth challenge was cancelled.') {\n    console.error('Login denied in the board UI. Re-run and approve to continue.');\n    return;\n  }\n  throw err;\n}","preventionTips":["Tell the user the approval URL is single-use and must be approved, not closed.","In automation, do not leave loginBoardCli polling unattended — wrap it so a denial surfaces cleanly.","If multiple operators share the instance, coordinate who will approve each login."],"tags":["auth","cli","board-auth","user-action"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}