{"record":{"id":"dd0764cabcf49807","repo":"nexu-io/open-design","slug":"od-critique-fallback-policy-must-be-one-of-fallb","errorCode":null,"errorMessage":"OD_CRITIQUE_FALLBACK_POLICY must be one of ${FALLBACK_POLICIES.join(', ')}, got \"${raw}\"","messagePattern":"OD_CRITIQUE_FALLBACK_POLICY must be one of (.+?), got \"(.+?)\"","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/critique/config.ts","lineNumber":85,"sourceCode":"  const n = Number(raw);\n  if (!Number.isFinite(n) || n < 0) {\n    throw new RangeError(\n      `${key} must be a non-negative finite number, got \"${raw}\"`,\n    );\n  }\n  return n;\n}\n\nfunction parseFallbackPolicy(\n  raw: string | undefined,\n  fallback: CritiqueConfig['fallbackPolicy'],\n): CritiqueConfig['fallbackPolicy'] {\n  if (raw === undefined) return fallback;\n  const trimmed = raw.trim();\n  if (FALLBACK_POLICIES.includes(trimmed as CritiqueConfig['fallbackPolicy'])) {\n    return trimmed as CritiqueConfig['fallbackPolicy'];\n  }\n  throw new RangeError(\n    `OD_CRITIQUE_FALLBACK_POLICY must be one of ${FALLBACK_POLICIES.join(', ')}, got \"${raw}\"`,\n  );\n}\n","sourceCodeStart":67,"sourceCodeEnd":89,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/critique/config.ts#L67-L89","documentation":"Thrown by parseFallbackPolicy() (used by loadCritiqueConfigFromEnv for OD_CRITIQUE_FALLBACK_POLICY) as a RangeError when the value is set but not one of the allowed policies in FALLBACK_POLICIES (the canonical list from @open-design/contracts/critique). ${raw} is the offending input. The fallback policy controls what happens when a critique panelist degrades or fails, so an unknown value cannot be silently coerced.","triggerScenarios":"Setting OD_CRITIQUE_FALLBACK_POLICY to a string not in FALLBACK_POLICIES — typo, wrong casing, or a value from an older version of the contracts.","commonSituations":"Operator typed 'strict' instead of the actual policy name; casing mismatch (e.g. 'Pass' vs 'pass'); the policy enum was renamed in a contract bump but env was not updated.","solutions":["Use one of the policies printed in the error (FALLBACK_POLICIES.join(', ')) — exact casing, trimmed.","Unset OD_CRITIQUE_FALLBACK_POLICY to fall back to defaultCritiqueConfig().fallbackPolicy.","After a contracts upgrade, re-check the allowed list in @open-design/contracts/critique and update env accordingly."],"exampleFix":"# before: typo'd or wrong-cased policy\nOD_CRITIQUE_FALLBACK_POLICY=Strict\n\n# after: exact value from FALLBACK_POLICIES\nOD_CRITIQUE_FALLBACK_POLICY=pass   # or whichever the contracts define","handlingStrategy":"validation","validationCode":"import { FALLBACK_POLICIES } from '@open-design/contracts/critique';\nconst raw = process.env.OD_CRITIQUE_FALLBACK_POLICY?.trim();\nif (raw && !FALLBACK_POLICIES.includes(raw as any)) {\n  throw new RangeError(`unsupported fallback policy: ${raw}`);\n}","typeGuard":"function isFallbackPolicy(raw: string, allowed: readonly string[]): raw is CritiqueConfig['fallbackPolicy'] {\n  return allowed.includes(raw);\n}","tryCatchPattern":"try { loadCritiqueConfigFromEnv(); }\ncatch (e) {\n  if (e instanceof RangeError && /FALLBACK_POLICY/.test(e.message)) {\n    // fall back to defaultCritiqueConfig().fallbackPolicy\n  } else throw e;\n}","preventionTips":["After a contracts upgrade, re-check FALLBACK_POLICIES and update env.","Document the allowed list wherever OD_CRITIQUE_FALLBACK_POLICY is referenced.","Lowercase/trim policy values in templated env to avoid casing drift."],"tags":["critique","config","env-vars","range-error","boot"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}