{"record":{"id":"f271ec29e1b8ff09","repo":"eyaltoledano/claude-task-master","slug":"fallbackitemextractor-must-be-a-function","errorCode":null,"errorMessage":"fallbackItemExtractor must be a function","messagePattern":"fallbackItemExtractor must be a function","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/utils/stream-parser.js","lineNumber":80,"sourceCode":"\t\t\tthrow new Error('maxBufferSize must be positive');\n\t\t}\n\t\tif (this.expectedTotal < 0) {\n\t\t\tthrow new Error('expectedTotal cannot be negative');\n\t\t}\n\t\tif (this.estimateTokens && typeof this.estimateTokens !== 'function') {\n\t\t\tthrow new Error('estimateTokens must be a function');\n\t\t}\n\t\tif (this.onProgress && typeof this.onProgress !== 'function') {\n\t\t\tthrow new Error('onProgress must be a function');\n\t\t}\n\t\tif (this.onError && typeof this.onError !== 'function') {\n\t\t\tthrow new Error('onError must be a function');\n\t\t}\n\t\tif (\n\t\t\tthis.fallbackItemExtractor &&\n\t\t\ttypeof this.fallbackItemExtractor !== 'function'\n\t\t) {\n\t\t\tthrow new Error('fallbackItemExtractor must be a function');\n\t\t}\n\t\tif (this.itemValidator && typeof this.itemValidator !== 'function') {\n\t\t\tthrow new Error('itemValidator must be a function');\n\t\t}\n\t}\n\n\tstatic defaultItemValidator(item) {\n\t\treturn (\n\t\t\titem && item.title && typeof item.title === 'string' && item.title.trim()\n\t\t);\n\t}\n}\n\n/**\n * Manages progress tracking and metadata\n */\nclass ProgressTracker {\n\tconstructor(config) {","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/src/utils/stream-parser.js#L62-L98","documentation":"The fallbackItemExtractor option must be a callable used to salvage items from raw text when JSON path extraction fails. The constructor throws if the value is truthy but not a function. Fail-fast validation prevents mid-stream crashes in the fallback path.","triggerScenarios":"new StreamParser({ jsonPaths: ['$.items'], fallbackItemExtractor: true }) or passing a string/object (e.g. a regex or extractor descriptor) instead of a function.","commonSituations":"Passing a regex intended to be used for extraction (the library expects a function); config-driven wiring with serialized placeholders; copy-paste of an option name from a different library.","solutions":["Pass a function: fallbackItemExtractor: (text) => [...text.matchAll(/\\{[^}]+\\}/g)].map(m => JSON.parse(m[0])).","If using a regex, wrap it in a function that applies it.","Remove the option to rely on default extraction behavior."],"exampleFix":"// before\nnew StreamParser({ jsonPaths: ['$.items'], fallbackItemExtractor: /\\{.*\\}/g })\n// after\nnew StreamParser({ jsonPaths: ['$.items'], fallbackItemExtractor: (text) => text.match(/\\{.*\\}/g)?.map(JSON.parse) ?? [] })","handlingStrategy":"type-guard","validationCode":"if (options.fallbackItemExtractor != null && typeof options.fallbackItemExtractor !== 'function') {\n  throw new TypeError('fallbackItemExtractor must be a function');\n}","typeGuard":"function isExtractor(v) {\n  return typeof v === 'function' && v.length <= 1;\n}","tryCatchPattern":"try {\n  return new StreamParser(options);\n} catch (err) {\n  if (err.message === 'fallbackItemExtractor must be a function') {\n    const { fallbackItemExtractor, ...rest } = options;\n    return new StreamParser(rest);\n  }\n  throw err;\n}","preventionTips":["Remember the option takes (text) => items[], not a regex/schema.","Wrap regexes: (text) => text.match(re) ?? [].","Sanity-test your extractor with sample truncated output before deploying."],"tags":["configuration","validation","callbacks"],"backgroundTag":"wrong-argument-type","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}