cheeriojs/cheerio · error · TypeError
Expected a string
Error message
Expected a string
What it means
cheerio's stream API (the Writable returned for streaming parsing) is created with decodeStrings: false, so every chunk written to it must already be a string. Writing a Buffer (or Uint8Array) hits the typeof chunk !== 'string' check and throws 'Expected a string'.
Source
Thrown at src/index.ts:88
return load(str, opts);
}
function _stringStream(
options: InternalOptions | undefined,
cb: (err: Error | null | undefined, $: CheerioAPI) => void,
): Writable {
if (options?._useHtmlParser2) {
const parser = htmlparser2.createDocumentStream(
(err, document) => cb(err, load(document, options)),
options,
);
return new Writable({
decodeStrings: false,
write(chunk, _encoding, callback) {
if (typeof chunk !== 'string') {
throw new TypeError('Expected a string');
}
parser.write(chunk);
callback();
},
final(callback) {
parser.end();
callback();
},
});
}
options ??= {};
options.treeAdapter ??= htmlparser2Adapter;
if (options.scriptingEnabled !== false) {
options.scriptingEnabled = true;
}View on GitHub (pinned to a1be131f9b)
Solutions
- Call source.setEncoding('utf8') before piping the readable stream into cheerio
- Convert Buffers to strings in a transform: .pipe(new Transform({transform(c,e,cb){cb(null,c.toString())}}))
- If in the browser, decode bytes via TextDecoder before writing
Example fix
// before
fs.createReadStream('page.html').pipe(cheerioStream);
// after
fs.createReadStream('page.html', { encoding: 'utf8' }).pipe(cheerioStream); Defensive patterns
Strategy: validation
Validate before calling
source.setEncoding('utf8'); // before pipe
// or when writing manually:
stream.write(typeof chunk === 'string' ? chunk : chunk.toString('utf8')); Type guard
const isStringChunk = (c: unknown): c is string => typeof c === 'string';
Try / catch
// Prefer validation over catching: decode strings before writing.
// If unavoidable:
try { stream.write(data); } catch (e) { if (e instanceof TypeError && /Expected a string/.test(e.message)) stream.write(String(data)); else throw e; } Prevention
- Always set an encoding on readable streams piped into cheerio
- Insert a Buffer-to-string Transform in binary pipelines
- Never write Uint8Array/Buffer directly to cheerio's writable
When it happens
Trigger: Piping a Buffer-producing stream (e.g. fs.createReadStream, http response with default encoding) into cheerio's stream without setting an encoding; calling stream.write(Buffer.from('<div>')) directly.
Common situations: Piping fs file streams or HTTP responses into the streaming parser; forgetting stream.setEncoding('utf8') before pipe; mixing Buffer-based pipelines with cheerio's string-only writable.
Related errors
- Bad combination of arguments.
- The content-type "${mimeType.essence}" is neither HTML nor X
- cheerio.load() expects a string
- Unexpected type of selector
AI-assisted analysis of cheeriojs/cheerio@a1be131f9b (2026-08-28).
Data as JSON: /api/errors/ccda84c0d6057e0d.
Report an issue: GitHub.