eyaltoledano/claude-task-master · error
estimateTokens must be a function
Error message
estimateTokens must be a function
What it means
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.
Source
Thrown at src/utils/stream-parser.js:68
this.validate();
}
validate() {
if (!this.jsonPaths || !Array.isArray(this.jsonPaths)) {
throw new Error('jsonPaths is required and must be an array');
}
if (this.jsonPaths.length === 0) {
throw new Error('jsonPaths array cannot be empty');
}
if (this.maxBufferSize <= 0) {
throw new Error('maxBufferSize must be positive');
}
if (this.expectedTotal < 0) {
throw new Error('expectedTotal cannot be negative');
}
if (this.estimateTokens && typeof this.estimateTokens !== 'function') {
throw new Error('estimateTokens must be a function');
}
if (this.onProgress && typeof this.onProgress !== 'function') {
throw new Error('onProgress must be a function');
}
if (this.onError && typeof this.onError !== 'function') {
throw new Error('onError must be a function');
}
if (
this.fallbackItemExtractor &&
typeof this.fallbackItemExtractor !== 'function'
) {
throw new Error('fallbackItemExtractor must be a function');
}
if (this.itemValidator && typeof this.itemValidator !== 'function') {
throw new Error('itemValidator must be a function');
}
}
View on GitHub (pinned to c0c98d367c)
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.
Example fix
// before
new StreamParser({ jsonPaths: ['$.items'], estimateTokens: 'estimateTokens' })
// after
const estimateTokens = (item) => Math.ceil(JSON.stringify(item).length / 4);
new StreamParser({ jsonPaths: ['$.items'], estimateTokens }) Defensive patterns
Strategy: type-guard
Validate before calling
if (options.estimateTokens != null && typeof options.estimateTokens !== 'function') {
throw new TypeError('estimateTokens must be a function');
} Type guard
function isCallable(v) {
return typeof v === 'function';
} Try / catch
try {
return new StreamParser(options);
} catch (err) {
if (err.message === 'estimateTokens must be a function') {
const { estimateTokens, ...rest } = options;
return new StreamParser(rest); // drop invalid callback
}
throw err;
} Prevention
- 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.
When it happens
Trigger: new StreamParser({ jsonPaths: [...], estimateTokens: true }), estimateTokens: 'someTokenCounter' (passing a name instead of a reference), or a misconfigured DI container returning undefined-wrapped values.
Common situations: 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.
Understand the failure class
Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.
Related errors
- MISSING_CONFIGURATION
- INVALID_INPUT
- Unknown provider '${providerName}' for API key resolution.
- Parameter validation failed: ${errors.join('; ')}
- ${this.name} Model ID is required
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/2b9fac0315ef98e2.
Report an issue: GitHub.