{"record":{"id":"b478e99161669f98","repo":"paperclipai/paperclip","slug":"invalid-response","errorCode":"invalid_response","errorMessage":"invalid_response","messagePattern":"invalid_response","errorType":"error_code","errorClass":"RequestFailure","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-discord-command-registration.ts","lineNumber":322,"sourceCode":"function abortable<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n  return new Promise<T>((resolve, reject) => {\n    const abort = () => reject(new RequestFailure(\"request_failed\"));\n    signal.addEventListener(\"abort\", abort, { once: true });\n    if (signal.aborted) abort();\n    promise\n      .then(resolve, reject)\n      .finally(() => signal.removeEventListener(\"abort\", abort));\n  });\n}\n\nasync function request(\n  input: ReconcileDiscordCommandRegistrationOptions,\n  method: \"GET\" | \"POST\" | \"PATCH\",\n  commandId?: string,\n): Promise<unknown> {\n  const timeoutMs = input.requestTimeoutMs ?? 25_000;\n  if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 25_000)\n    throw new RequestFailure(\"invalid_response\");\n  const signal = AbortSignal.timeout(timeoutMs);\n  let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n  try {\n    const response = await abortable(\n      input.fetch(\n        `https://discord.com/api/v10/applications/${input.scope.applicationId}/commands${commandId ? `/${commandId}` : \"\"}`,\n        {\n          method,\n          signal,\n          redirect: \"error\",\n          headers: {\n            authorization: `Bot ${input.botToken}`,\n            ...(method === \"GET\" ? {} : { \"content-type\": \"application/json\" }),\n          },\n          ...(method === \"GET\"\n            ? {}\n            : {\n                body: JSON.stringify(","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-discord-command-registration.ts#L304-L340","documentation":"request() in the Discord command-registration reconciler validates requestTimeoutMs before making the Discord API call; if it is not an integer between 1 and 25000 inclusive it throws a RequestFailure with code 'invalid_response'. The message is terse because the guard runs before any network I/O — it is a pre-flight configuration validation, not Discord's reply.","triggerScenarios":"Calling the reconciler (reconcileDiscordCommandRegistration path) with input.requestTimeoutMs set to 0, a negative number, a non-integer (e.g. 1500.5), or greater than 25000 (e.g. 60000 for a slow network).","commonSituations":"Operator sets a timeout above the 25s ceiling in config; a duration in seconds (e.g. 30) passed where milliseconds are expected (0.03 would also fail the integer check... 30 fails as <1ms semantics confusion); NaN from an unparsed env var like Number('25s').","solutions":["Set input.requestTimeoutMs to an integer between 1 and 25000 (e.g. 25000 for the maximum).","Omit requestTimeoutMs entirely to use the default of 25000.","Check the units — pass milliseconds, not seconds, and parse env values with Number() guarding against NaN.","Clamp the value on the caller side: Math.min(25000, Math.max(1, Math.floor(ms)))."],"exampleFix":"// before\nreconcile({ ..., requestTimeoutMs: Number(process.env.TIMEOUT_S) }) // '30' -> 30000 -> RequestFailure invalid_response\n// after\nconst ms = Math.min(25000, Math.max(1, Math.floor(Number(process.env.TIMEOUT_S) * 1000 || 25000)));\nreconcile({ ..., requestTimeoutMs: ms });","handlingStrategy":"validation","validationCode":"if (!Number.isInteger(requestTimeoutMs) || requestTimeoutMs < 1 || requestTimeoutMs > 25000) throw new Error('requestTimeoutMs must be an integer in [1, 25000] ms');","typeGuard":"const isValidTimeoutMs = (v) => Number.isInteger(v) && v >= 1 && v <= 25000;","tryCatchPattern":"try {\n  return await reconcileDiscordCommands(input);\n} catch (e) {\n  if (e?.code === 'invalid_response') {\n    return reconcileDiscordCommands({ ...input, requestTimeoutMs: 25000 }); // fall back to default\n  }\n  throw e;\n}","preventionTips":["Pass milliseconds, not seconds, for requestTimeoutMs.","Omit the field to use the default 25000 ms instead of computing a custom value.","Clamp config-derived values to the [1, 25000] range before calling.","Guard Number(env) results against NaN before use."],"tags":["validation","timeout","discord","configuration","request"],"backgroundTag":"invalid-config-value","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}