{"record":{"id":"d623ebce50861330","repo":"affaan-m/ECC","slug":"capsule-payload-denied","errorCode":"capsule.payload_denied","errorMessage":"payload keys not allowlisted: ${dropped.join(', ')}","messagePattern":"payload keys not allowlisted: (.+?)","errorType":"exception","errorClass":"CapsuleError","httpStatus":null,"severity":"error","filePath":"scripts/lib/eval-harness/capsule.js","lineNumber":194,"sourceCode":"   * A partial I/O failure is preserved for diagnosis, never silently rolled back.\n   */\n  append(lineage, kind, payload = {}, options = {}) {\n    return withAppendLock(this.dir, () => {\n      const state = readCapsule(this.dir);\n      if (!state.ok) throw new CapsuleError(state.code, state.reason, { failed_at: state.failed_at });\n      if (!envelope.LINEAGES.includes(lineage)) {\n        throw new CapsuleError('capsule.bad_lineage', `unknown lineage ${lineage}`);\n      }\n      const effectClass = options.effect_class || 'SE0';\n      const { payload: clean, dropped, findings, errors: payloadErrors } = envelope.redactPayload(payload, options);\n      if (payloadErrors.length > 0) {\n        throw new CapsuleError('capsule.payload_invalid', payloadErrors.join('; '));\n      }\n      if (findings.length > 0) {\n        throw new CapsuleError('capsule.secret_canary', `payload tripped secret canary ${findings[0].canary} at ${findings[0].path}`, { findings });\n      }\n      if (dropped.length > 0 && options.strict !== false) {\n        throw new CapsuleError('capsule.payload_denied', `payload keys not allowlisted: ${dropped.join(', ')}`, { dropped });\n      }\n      const body = {\n        schema: envelope.SCHEMA_VERSION,\n        run_id: state.meta.run_id,\n        capsule_id: state.meta.capsule_id,\n        seq: state.entries.length,\n        ts: nowIso(this.clock),\n        lineage,\n        kind,\n        effect_class: effectClass,\n        harness_version: state.meta.harness_version,\n        task_family: state.meta.task_family,\n        parent_hash: state.root_hash,\n        payload: clean,\n      };\n      const entry = { ...body, entry_hash: envelope.computeEntryHash(body) };\n      const errors = envelope.validateEnvelope(entry);\n      if (errors.length > 0) throw new CapsuleError('capsule.invalid_entry', errors.join('; '));","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/eval-harness/capsule.js#L176-L212","documentation":"redactPayload() drops any payload keys not on the allowlist for the given lineage/kind, returning them in the dropped array. By default (strict mode) append() rejects the call with 'capsule.payload_denied' listing the disallowed keys instead of silently discarding data. Callers may explicitly opt out with options.strict === false to accept key dropping.","triggerScenarios":"Calling append() with payload keys that are not allowlisted for that entry type — e.g. adding custom fields like { foo: 1 } to a lineage whose envelope only permits { msg } or defined fields, or renaming a field without updating the allowlist.","commonSituations":"Adding extra debugging fields 'just this once'; a refactor renaming a payload field (e.g. error -> message) so the old key is no longer allowlisted; passing the whole request/config object as payload.","solutions":["Read the dropped list in the message and either remove those keys or rename them to allowlisted ones.","Set options.strict = false only if silently dropping the extra keys is acceptable.","If the field is genuinely needed, extend the payload allowlist in envelope.redactPayload for that lineage/kind.","Project payloads down to the documented minimal schema per entry kind."],"exampleFix":"// before\nawait capsule.append('fix', 'note', { msg: 'ok', traceId: 'abc' }); // capsule.payload_denied\n\n// after: only allowlisted keys\nawait capsule.append('fix', 'note', { msg: 'ok traceId=abc' });\n// or opt into dropping:\nawait capsule.append('fix', 'note', { msg: 'ok', traceId: 'abc' }, { strict: false });","handlingStrategy":"validation","validationCode":"const { dropped } = envelope.redactPayload(payload, {});\nif (dropped.length > 0) console.warn(`keys will be rejected/dropped: ${dropped.join(', ')}`);","typeGuard":"function hasOnlyAllowlistedKeys(payload, allow) {\n  return Object.keys(payload).every(k => allow.includes(k));\n}","tryCatchPattern":"try {\n  await capsule.append(lineage, kind, payload);\n} catch (e) {\n  if (e instanceof CapsuleError && e.code === 'capsule.payload_denied') {\n    const extra = e.detail?.dropped ?? [];\n    const trimmed = Object.fromEntries(Object.entries(payload).filter(([k]) => !extra.includes(k)));\n    return capsule.append(lineage, kind, trimmed);\n  }\n  throw e;\n}","preventionTips":["Keep payload keys to the documented per-lineage schema.","When renaming payload fields, update the allowlist in the same PR.","Never dump whole config/request objects into payloads.","Decide explicitly whether strict mode should stay on for your workload."],"tags":["payload","allowlist","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}