paperclipai/paperclip · error · Error
Invalid Discord command registration authority
Error message
Invalid Discord command registration authority
What it means
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'.
Source
Thrown at server/src/services/chat-discord-command-registration.ts:426
* reconciliation identity; the marker alone never grants command ownership.
* Unknown writes remain attempted until GET shows the exact expected command.
* An absent command after timeout is NOT proof that the POST never committed.
*/
export async function reconcileDiscordCommandRegistration(
input: ReconcileDiscordCommandRegistrationOptions,
): Promise<DiscordCommandRegistrationResult> {
let state = parseDiscordCommandRegistration(input.state, input.scope, true);
const runtimeFence = fenceSchema.safeParse(input.runtimeFence);
if (
!state ||
!runtimeFence.success ||
input.verifiedIdentity.botExternalId !== input.scope.applicationId ||
input.verifiedIdentity.providerAccountId !== input.scope.guildId ||
!input.botToken ||
input.botToken.length > 4096 ||
/[\r\n]/.test(input.botToken)
) {
throw new Error("Invalid Discord command registration authority");
}
// The caller may retain its options while an authorization hook is held.
// Snapshot the validated identity, credential and HTTP function before await.
input = {
...input,
scope: state.scope,
state,
runtimeFence: Object.freeze(runtimeFence.data),
verifiedIdentity: Object.freeze({ ...input.verifiedIdentity }),
};
const authorize = async (stage: DiscordCommandRegistrationStage) => {
try {
await input.authorize(stage);
} catch {
throw new Error("Discord command registration authorization denied");
}
};
const persist = async (next: DiscordCommandRegistration) => {View on GitHub (pinned to 01ad858492)
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.
Example fix
// before const token = process.env.DISCORD_BOT_TOKEN; // may contain \n // after const token = process.env.DISCORD_BOT_TOKEN?.trim();
Defensive patterns
Strategy: validation
Validate before calling
const ok =
state &&
verifiedIdentity.botExternalId === scope.applicationId &&
verifiedIdentity.providerAccountId === scope.guildId &&
botToken && botToken.length <= 4096 && !/[\r\n]/.test(botToken);
if (!ok) throw new Error("registration authority mismatch before calling reconcile"); Type guard
const validAuthority = (i: ReconcileDiscordCommandRegistrationOptions) => Boolean(i.botToken) && i.botToken.length <= 4096 && !/[\r\n]/.test(i.botToken) && i.verifiedIdentity.botExternalId === i.scope.applicationId && i.verifiedIdentity.providerAccountId === i.scope.guildId;
Try / catch
try { await reconcileDiscordCommandRegistration(input); }
catch (e) { if ((e as Error).message.includes("Invalid Discord command registration authority")) { await reverifyIdentityAndReseedState(); return retry(); } throw e; } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- invalid_response
- ${label} must be an integer between 1 and ${maximum}.
- PAPERCLIP_EVAL_MAX_CAMPAIGN_COST_USD must be a positive fini
- Runner live rotation requires a valid generated-at time
- --agent-name cannot be empty.
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/8f354e3d0da1b2f2.
Report an issue: GitHub.