{"record":{"id":"7a2dcd04150e96e7","repo":"can1357/oh-my-pi","slug":"match-case-values-must-be-functions","errorCode":null,"errorMessage":"match case values must be functions","messagePattern":"match case values must be functions","errorType":"exception","errorClass":"OmpTypeError","httpStatus":null,"severity":"error","filePath":"packages/omptype/src/type.ts","lineNumber":2863,"sourceCode":"\tin<narrowed>(): MatchParser<narrowed, output>;\n\tin<const definition>(definition: definition): MatchParser<InferDef<definition>, output>;\n}\n\ninterface MatchBranch {\n\treadonly definition: unknown;\n\treadonly schema: BaseType;\n\treadonly resolve: (input: unknown, ...args: readonly unknown[]) => unknown;\n}\n\ninterface MatchState {\n\treadonly parse: (definition: unknown) => BaseType;\n\treadonly branches: readonly MatchBranch[];\n\treadonly input?: BaseType;\n\treadonly key?: PropertyKey;\n}\n\nfunction caseResolver(value: unknown): (input: unknown, ...args: readonly unknown[]) => unknown {\n\tif (typeof value !== \"function\") throw new OmpTypeError(\"match case values must be functions\");\n\treturn (input, ...args) => Reflect.apply(value, undefined, [input, ...args]);\n}\n\nfunction unionIR(branches: readonly MatchBranch[]): IR {\n\tconst members = branches.map(branch => branch.schema.ir);\n\tif (members.length === 0) return { k: \"never\" };\n\tif (members.length === 1) return members[0];\n\treturn { k: \"union\", members };\n}\n\nfunction publicMatcher<input, output>(\n\tstate: MatchState,\n\tfallback: MatchDefault<input, output>,\n): Matcher<input, output> {\n\tconst fallbackResolver = typeof fallback === \"function\" ? caseResolver(fallback) : undefined;\n\tconst casesIR = unionIR(state.branches);\n\tlet casesSchema: BaseType;\n\tif (state.key === undefined || state.branches.length === 0) {","sourceCodeStart":2845,"sourceCodeEnd":2881,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/omptype/src/type.ts#L2845-L2881","documentation":"caseResolver() converts match-case values into resolver functions; a case value that is not a function throws OmpTypeError. Match cases are expected to supply handlers (functions of the input) rather than plain values, so a non-function is a misuse of the match API.","triggerScenarios":"Passing a non-function as a match case value, e.g. match({ 'string': 'fallback' }) or cases built from data where an entry is a constant/schema instead of a handler function.","commonSituations":"Confusing value-match with handler-match syntax; JSON-driven case tables where values deserialize as strings/numbers; refactoring from a value API to a function API without wrapping constants.","solutions":["Wrap the value in a function: () => 'fallback' instead of 'fallback'","If you need a schema as a case, use the API that accepts a schema, not caseResolver's function path","Validate dynamically built case maps with typeof value === 'function' before passing them","Check that your case object keys map to handler functions, not result constants"],"exampleFix":"// before\nmatch({ 'string': 'it was a string' }); // throws\n// after\nmatch({ 'string': () => 'it was a string' });","handlingStrategy":"validation","validationCode":"function assertFunctionCases(cases: Record<string, unknown>) {\n  for (const [key, value] of Object.entries(cases)) {\n    if (typeof value !== 'function') {\n      throw new Error(`match case \"${key}\" must be a function`);\n    }\n  }\n}","typeGuard":"function isHandlerMap(cases: Record<string, unknown>): cases is Record<string, (input: unknown) => unknown> {\n  return Object.values(cases).every(v => typeof v === 'function');\n}","tryCatchPattern":"try {\n  const m = match(cases);\n} catch (err) {\n  if (err instanceof OmpTypeError && err.message === 'match case values must be functions') {\n    throw new Error('Wrap constant results in functions: value -> () => value');\n  }\n  throw err;\n}","preventionTips":["Always write match cases as handler functions, even for constants","Validate data-driven case maps with typeof before use","Type case maps as Record<string, (input: unknown) => unknown> so the compiler catches constants"],"tags":["match","schema","type-mismatch","omptype"],"backgroundTag":"invalid-match-case","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}