{"record":{"id":"4d0c946842b3285f","repo":"affaan-m/ECC","slug":"label-must-be-one-of-allowed-join","errorCode":null,"errorMessage":"${label} must be one of: ${allowed.join(', ')}.","messagePattern":"(.+?) must be one of: (.+?)\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/memory-vault-format.js","lineNumber":94,"sourceCode":"\nfunction asNonEmptyString(value, label, maxChars = 10_000) {\n  if (typeof value !== 'string' || value.trim().length === 0) {\n    throw new Error(`${label} must be a non-empty string.`);\n  }\n  const normalized = value.trim();\n  if (normalized.length > maxChars) {\n    throw new Error(`${label} is too long (maximum ${maxChars} characters).`);\n  }\n  if (hasUnsafeControlCharacters(normalized)) {\n    throw new Error(`${label} must not contain control or bidirectional formatting characters.`);\n  }\n  return normalized;\n}\n\nfunction validateEnum(value, allowed, label) {\n  const normalized = asNonEmptyString(value, label, 64);\n  if (!allowed.includes(normalized)) {\n    throw new Error(`${label} must be one of: ${allowed.join(', ')}.`);\n  }\n  return normalized;\n}\n\nfunction validateSlug(value, label) {\n  const normalized = asNonEmptyString(value, label, 64);\n  if (!SLUG_PATTERN.test(normalized)) {\n    throw new Error(`${label} must be a lowercase letters/numbers slug.`);\n  }\n  return normalized;\n}\n\nfunction validateMemoryId(value) {\n  const normalized = asNonEmptyString(value, 'memory id', 132);\n  if (!MEMORY_ID_PATTERN.test(normalized)) {\n    throw new Error('memory id must match mem_<lowercase-id> and cannot contain a path.');\n  }\n  return normalized;","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/memory-vault-format.js#L76-L112","documentation":"Thrown by validateEnum() when the value (after trimming and length-check) is not in the allowed list. Used for memory fields with a closed value set: kind (context/decision/fact/...), scope (project/team/user), trust (unreviewed), status (active/rejected/superseded), and similar.","triggerScenarios":"Setting kind to 'bug', scope to 'org', status to 'closed', or any value outside the frozen enum arrays.","commonSituations":"Guessing an enum value instead of checking the schema; copy-pasting from a different memory system; version skew if a new enum value was added upstream but the validator is older.","solutions":["Read the allowed values listed in the error message and pick one exactly.","If you believe the value should be valid, upgrade the memory-vault module to a version that includes it.","Avoid inventing values; if none fit, use the closest 'note' kind and add detail in the body."],"exampleFix":"# before\nkind: bug\n# after\nkind: note","handlingStrategy":"validation","validationCode":"const ALLOWED_KINDS = ['context','decision','fact','handoff','lesson','note','preference','runbook'];\nfunction isValidEnum(value, allowed) {\n  return typeof value === 'string' && allowed.includes(value.trim());\n}\nif (!isValidEnum(kind, ALLOWED_KINDS)) {\n  throw new Error(`kind must be one of: ${ALLOWED_KINDS.join(', ')}`);\n}","typeGuard":"function isMemoryKind(value) {\n  return ['context','decision','fact','handoff','lesson','note','preference','runbook'].includes(value);\n}","tryCatchPattern":"try {\n  result = validateEnum(value, allowed, label);\n} catch (e) {\n  if (/must be one of:/.test(e.message)) result = validateEnum('note', allowed, label);\n  else throw e;\n}","preventionTips":["Populate enum dropdowns from the same frozen arrays the validator uses.","Reject documents early at the API boundary if an enum field is invalid.","Document the closed enum sets in your schema reference."],"tags":["memory-vault","validation","enum","schema"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}