{"record":{"id":"68e7e367f7e2aac9","repo":"denoland/deno","slug":"err-invalid-this","errorCode":"ERR_INVALID_THIS","errorMessage":"Value of \"this\" must be of type StringDecoder","messagePattern":"Value of \"this\" must be of type StringDecoder","errorType":"exception","errorClass":"ERR_INVALID_THIS","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/string_decoder.ts","lineNumber":328,"sourceCode":"      bufLen = 0;\n      break;\n  }\n  this.encoding = normalizedEncoding;\n  this.lastChar = Buffer.allocUnsafe(bufLen);\n  this.enc = enc;\n  this[kBufferedBytes] = 0;\n  this[kMissingBytes] = 0;\n  this.flush = flush;\n  this.decode = decode;\n}\n\nStringDecoder.prototype.write = function write(buf) {\n  if (typeof buf === \"string\") {\n    return buf;\n  }\n  const normalizedBuf = normalizeBuffer(buf);\n  if (this[kBufferedBytes] === undefined) {\n    throw new ERR_INVALID_THIS(\"StringDecoder\");\n  }\n  return this.decode(normalizedBuf);\n};\n\nStringDecoder.prototype.end = function end(buf) {\n  let ret = \"\";\n  if (buf !== undefined) {\n    ret = this.write(buf);\n  }\n  if (this[kBufferedBytes] > 0) {\n    ret += this.flush();\n  }\n  return ret;\n};\n\nStringDecoder.prototype.text = function text(buf, offset) {\n  this[kBufferedBytes] = 0;\n  this[kMissingBytes] = 0;","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/string_decoder.ts#L310-L346","documentation":"StringDecoder stores its internal state under a private symbol (kBufferedBytes) that only the constructor initializes. StringDecoder.prototype.write() checks that the receiver carries that symbol and throws ERR_INVALID_THIS when it does not — i.e. the method was invoked on an object that was not built by `new StringDecoder(...)`. This mirrors Node's guard against borrowed or detached instance methods.","triggerScenarios":"StringDecoder.prototype.write.call({}, buf); creating an instance via Object.create(StringDecoder.prototype) instead of new; a subclass whose constructor forgets to call super(encoding); passing decoder.write as a bare callback so it is later invoked with a foreign `this`.","commonSituations":"Subclassing StringDecoder without super(); registering decoder.write directly as an event handler (emitter rebinds `this`); refactoring that destructures methods off the instance; mock/stub frameworks that re-invoke captured methods with a substitute receiver.","solutions":["Always construct with new StringDecoder(encoding) and invoke write/end on that exact instance","When subclassing, call super(encoding) as the first statement of the constructor","Bind methods before handing them to callbacks: emitter.on('data', decoder.write.bind(decoder)) or wrap in an arrow function","If the value's origin is uncertain, check `instanceof StringDecoder` before calling write"],"exampleFix":"// before\nsocket.on('data', decoder.write); // `this` is the socket, not the decoder\n\n// after\nsocket.on('data', (chunk) => decoder.write(chunk));","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"import { StringDecoder } from 'node:string_decoder';\n\nconst isStringDecoder = (v) =>\n  v instanceof StringDecoder &&\n  typeof v.write === 'function' &&\n  typeof v.end === 'function';\n\n// before calling\nif (!isStringDecoder(decoder)) {\n  throw new TypeError('decoder must be constructed with new StringDecoder()');\n}\nreturn decoder.write(chunk);","tryCatchPattern":"try {\n  out = decoder.write(chunk);\n} catch (err) {\n  if (err?.code === 'ERR_INVALID_THIS') {\n    // call-site bug: fix the receiver (bind or wrap), do not retry the same call\n    throw new Error('StringDecoder method called with wrong `this`; bind it to the instance');\n  }\n  throw err;\n}","preventionTips":["Only call write/end on the object returned by new StringDecoder(encoding)","Bind methods when passing them as callbacks: emitter.on('data', decoder.write.bind(decoder))","In subclasses, call super(encoding) first in the constructor","Treat ERR_INVALID_THIS as a call-shape bug — fix the call site instead of adding data checks"],"tags":["string-decoder","this-binding","api-misuse","node-compat"],"backgroundTag":"invalid-this","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}