{"record":{"id":"832d0c27530570b4","repo":"paperclipai/paperclip","slug":"invalid-discord-correction-binding","errorCode":null,"errorMessage":"Invalid Discord correction binding","messagePattern":"Invalid Discord correction binding","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-discord-question-forms.ts","lineNumber":200,"sourceCode":"          `${child.label}: This draft was shortened to ${maximum} characters.`,\n        );\n    } else if (child.options.some((option) => option.value === value))\n      values[child.id] = value;\n  }\n  const {\n    modal: _modal,\n    values: _values,\n    fieldErrors: _errors,\n    parentExpiresAt: _expiry,\n    ...binding\n  } = input;\n  const draft: DiscordQuestionFormCorrectionDraft = {\n    ...binding,\n    version: 1,\n    expiresAt: expiresAt.toISOString(),\n    values,\n  };\n  if (!validDraft(draft)) throw new Error(\"Invalid Discord correction binding\");\n  const actionId = correctionId(scope, input, input.submitActionId);\n  for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt++) {\n    const prior = await persistence.read(scope, stateKey(actionId));\n    if (\n      await persistence.compareAndSet({\n        ...scope,\n        key: stateKey(actionId),\n        expectedVersion: prior?.version ?? null,\n        value: draft,\n        expiresAt,\n      })\n    ) {\n      return {\n        action: \"errors\",\n        errors: input.fieldErrors,\n        paperclipDiscordCorrection: {\n          version: 1,\n          actionId,","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-discord-question-forms.ts#L182-L218","documentation":"After constructing the DiscordQuestionFormCorrectionDraft from the binding, the code re-validates it with validDraft(draft). This error means the assembled draft failed internal validation — e.g. the spread binding plus version/expiresAt/values produced a structurally invalid draft, or input.values contained entries that don't validate.","triggerScenarios":"The binding object passed into retainDiscordQuestionFormCorrection is missing required fields or has wrong types; values derived from the modal do not satisfy validDraft's invariants (e.g. non-string or disallowed values); expiresAt serialization is malformed.","commonSituations":"A caller passes a partially-constructed or corrupted binding loaded from persistence; a schema migration changed the draft shape so older stored bindings no longer validate; a bug in value coercion produces an invalid draft.","solutions":["Log the draft passed to validDraft and fix the caller supplying the binding so all required fields are present and correctly typed","Re-issue a fresh correction flow instead of reusing a stored binding that no longer matches the current draft schema","Check for schema migrations between draft versions and migrate old stored bindings"],"exampleFix":"// before\nconst draft = { ...maybePartialBinding, version: 1 };\n// after\nif (!binding || typeof binding.values !== \"object\") throw new Error(\"binding incomplete\");\nconst draft = { ...binding, version: 1, expiresAt: expiresAt.toISOString(), values };","handlingStrategy":"validation","validationCode":"function validateBinding(binding) {\n  return binding && typeof binding === \"object\" &&\n    typeof binding.values === \"object\" && binding.values !== null &&\n    typeof binding.expiresAt === \"string\" && !isNaN(Date.parse(binding.expiresAt));\n}\nif (!validateBinding(inputBinding)) throw new Error(\"binding incomplete before retain\");","typeGuard":"const isDraftLike = (d) => !!d && typeof d === \"object\" && typeof d.version === \"number\" && typeof d.expiresAt === \"string\" && typeof d.values === \"object\";","tryCatchPattern":"try {\n  await retainDiscordQuestionFormCorrection(...);\n} catch (err) {\n  if (err.message === \"Invalid Discord correction binding\") {\n    // restart the correction flow with a fresh binding\n    return startFreshCorrection(scope, input);\n  }\n  throw err;\n}","preventionTips":["Validate the binding at the API boundary before calling retain","Keep draft schema versioned and migrate stored bindings when the schema changes","Serialize expiresAt with toISOString() only"],"tags":["discord","validation","invariant"],"backgroundTag":"internal-invariant-violation","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"}