{"record":{"id":"2b9fac0315ef98e2","repo":"eyaltoledano/claude-task-master","slug":"estimatetokens-must-be-a-function","errorCode":null,"errorMessage":"estimateTokens must be a function","messagePattern":"estimateTokens must be a function","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/utils/stream-parser.js","lineNumber":68,"sourceCode":"\n\t\tthis.validate();\n\t}\n\n\tvalidate() {\n\t\tif (!this.jsonPaths || !Array.isArray(this.jsonPaths)) {\n\t\t\tthrow new Error('jsonPaths is required and must be an array');\n\t\t}\n\t\tif (this.jsonPaths.length === 0) {\n\t\t\tthrow new Error('jsonPaths array cannot be empty');\n\t\t}\n\t\tif (this.maxBufferSize <= 0) {\n\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","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/src/utils/stream-parser.js#L50-L86","documentation":"When supplied, the estimateTokens option must be a callable used to estimate token counts for streamed items. The constructor throws if the value is truthy but not a function. Passing a non-function value indicates a wiring mistake, so fail-fast is preferred over runtime crashes mid-stream.","triggerScenarios":"new StreamParser({ jsonPaths: [...], estimateTokens: true }), estimateTokens: 'someTokenCounter' (passing a name instead of a reference), or a misconfigured DI container returning undefined-wrapped values.","commonSituations":"Passing the string name of a function instead of the function; importing a default export that is an object wrapping the counter; YAML/JSON config where only strings are representable.","solutions":["Pass an actual function: estimateTokens: (item) => JSON.stringify(item).length / 4.","If the value comes from config, look it up from a function registry instead of the raw config value.","Remove the option entirely if token estimation is not needed."],"exampleFix":"// before\nnew StreamParser({ jsonPaths: ['$.items'], estimateTokens: 'estimateTokens' })\n// after\nconst estimateTokens = (item) => Math.ceil(JSON.stringify(item).length / 4);\nnew StreamParser({ jsonPaths: ['$.items'], estimateTokens })","handlingStrategy":"type-guard","validationCode":"if (options.estimateTokens != null && typeof options.estimateTokens !== 'function') {\n  throw new TypeError('estimateTokens must be a function');\n}","typeGuard":"function isCallable(v) {\n  return typeof v === 'function';\n}","tryCatchPattern":"try {\n  return new StreamParser(options);\n} catch (err) {\n  if (err.message === 'estimateTokens must be a function') {\n    const { estimateTokens, ...rest } = options;\n    return new StreamParser(rest); // drop invalid callback\n  }\n  throw err;\n}","preventionTips":["Pass function references, not their string names.","If loading callbacks from config, map config keys to a function registry.","Wrap schema-based validators/zod in a function before passing.","Type-check options with JSDoc/TS so non-function callbacks fail at compile time."],"tags":["configuration","validation","types"],"backgroundTag":"wrong-argument-type","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}