{"record":{"id":"8f354e3d0da1b2f2","repo":"paperclipai/paperclip","slug":"invalid-discord-command-registration-authority","errorCode":null,"errorMessage":"Invalid Discord command registration authority","messagePattern":"Invalid Discord command registration authority","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-discord-command-registration.ts","lineNumber":426,"sourceCode":" * reconciliation identity; the marker alone never grants command ownership.\n * Unknown writes remain attempted until GET shows the exact expected command.\n * An absent command after timeout is NOT proof that the POST never committed.\n */\nexport async function reconcileDiscordCommandRegistration(\n  input: ReconcileDiscordCommandRegistrationOptions,\n): Promise<DiscordCommandRegistrationResult> {\n  let state = parseDiscordCommandRegistration(input.state, input.scope, true);\n  const runtimeFence = fenceSchema.safeParse(input.runtimeFence);\n  if (\n    !state ||\n    !runtimeFence.success ||\n    input.verifiedIdentity.botExternalId !== input.scope.applicationId ||\n    input.verifiedIdentity.providerAccountId !== input.scope.guildId ||\n    !input.botToken ||\n    input.botToken.length > 4096 ||\n    /[\\r\\n]/.test(input.botToken)\n  ) {\n    throw new Error(\"Invalid Discord command registration authority\");\n  }\n  // The caller may retain its options while an authorization hook is held.\n  // Snapshot the validated identity, credential and HTTP function before await.\n  input = {\n    ...input,\n    scope: state.scope,\n    state,\n    runtimeFence: Object.freeze(runtimeFence.data),\n    verifiedIdentity: Object.freeze({ ...input.verifiedIdentity }),\n  };\n  const authorize = async (stage: DiscordCommandRegistrationStage) => {\n    try {\n      await input.authorize(stage);\n    } catch {\n      throw new Error(\"Discord command registration authorization denied\");\n    }\n  };\n  const persist = async (next: DiscordCommandRegistration) => {","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-discord-command-registration.ts#L408-L444","documentation":"reconcileDiscordCommandRegistration validates its preconditions before doing any I/O: the persisted state must parse, the runtime fence schema must pass, the verified bot identity must match the scope's application/guild IDs, and the bot token must exist, be ≤4096 chars, and contain no CR/LF. Any mismatch throws 'Invalid Discord command registration authority'.","triggerScenarios":"Calling reconcile with a state blob from a different application/guild scope; verifiedIdentity.botExternalId not equal to scope.applicationId or providerAccountId not equal to scope.guildId; missing/empty bot token; token containing newlines (often from copy-paste or env files); malformed state or runtimeFence that fails fenceSchema.","commonSituations":"Bot token pasted with a trailing newline from a .env file; swapping Discord applications (new client id) without re-registering; state rows copied between companies/endpoints; identity verification run against a different guild than the registration scope.","solutions":["Trim the bot token of whitespace/newlines before storing (token may be ≤4096 chars, no CR/LF).","Ensure verifiedIdentity comes from a verification run against the same applicationId and guildId as scope.","Re-run identity verification and reconciliation as a unit so state, scope, and identity stay consistent.","Do not reuse registration state blobs across scopes; regenerate state for the target application/guild."],"exampleFix":"// before\nconst token = process.env.DISCORD_BOT_TOKEN; // may contain \\n\n// after\nconst token = process.env.DISCORD_BOT_TOKEN?.trim();","handlingStrategy":"validation","validationCode":"const ok =\n  state &&\n  verifiedIdentity.botExternalId === scope.applicationId &&\n  verifiedIdentity.providerAccountId === scope.guildId &&\n  botToken && botToken.length <= 4096 && !/[\\r\\n]/.test(botToken);\nif (!ok) throw new Error(\"registration authority mismatch before calling reconcile\");","typeGuard":"const validAuthority = (i: ReconcileDiscordCommandRegistrationOptions) =>\n  Boolean(i.botToken) && i.botToken.length <= 4096 && !/[\\r\\n]/.test(i.botToken) &&\n  i.verifiedIdentity.botExternalId === i.scope.applicationId &&\n  i.verifiedIdentity.providerAccountId === i.scope.guildId;","tryCatchPattern":"try { await reconcileDiscordCommandRegistration(input); }\ncatch (e) { if ((e as Error).message.includes(\"Invalid Discord command registration authority\")) { await reverifyIdentityAndReseedState(); return retry(); } throw e; }","preventionTips":["Trim bot tokens when reading from env/secrets to strip newlines.","Always pair identity verification and reconciliation against the same applicationId/guildId.","Never copy registration state blobs between scopes or companies."],"tags":["validation","discord","configuration"],"backgroundTag":"invalid-argument-value","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}