{"record":{"id":"ea135bac31dbe9d6","repo":"nodejs/node","slug":"und-err-destroyed","errorCode":"UND_ERR_DESTROYED","errorMessage":"The client is destroyed","messagePattern":"The client is destroyed","errorType":"exception","errorClass":"ClientDestroyedError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/dispatcher/dispatcher-base.js","lineNumber":165,"sourceCode":"      .then(() => queueMicrotask(onDestroyed))\n  }\n\n  dispatch (opts, handler) {\n    if (!handler || typeof handler !== 'object') {\n      throw new InvalidArgumentError('handler must be an object')\n    }\n\n    try {\n      if (!opts || typeof opts !== 'object') {\n        throw new InvalidArgumentError('opts must be an object.')\n      }\n\n      if (opts.dispatcher) {\n        throw new InvalidArgumentError('opts.dispatcher is not supported by instance methods. Pass opts.dispatcher to the top-level undici functions or call the dispatcher instance method directly.')\n      }\n\n      if (this[kDestroyed] || this[kOnDestroyed]) {\n        throw new ClientDestroyedError()\n      }\n\n      if (this[kClosed]) {\n        throw new ClientClosedError()\n      }\n\n      return this[kDispatch](opts, handler)\n    } catch (err) {\n      if (typeof handler.onResponseError !== 'function') {\n        throw err\n      }\n\n      handler.onResponseError(null, err)\n\n      return false\n    }\n  }\n}","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/dispatcher/dispatcher-base.js#L147-L183","documentation":"ClientDestroyedError (UND_ERR_DESTROYED) thrown by dispatch() when the client/dispatcher has been destroyed (or destruction is in progress, signalled by kOnDestroyed being populated). Once destroyed, the instance rejects all new dispatches. If the handler implements onResponseError, the error is delivered there instead of thrown.","triggerScenarios":"Calling `client.dispatch(...)` after `await client.destroy()` (or while destroy callbacks are still queued). Fires at dispatcher-base.js:164-165.","commonSituations":"Reusing a pooled client after a connection-error-triggered destroy; shutdown race where one path destroys while another dispatches; destroy-on-idle timeout firing mid-request; forgetting to create a fresh Client after teardown.","solutions":["Create a new Client/Pool after destroying the previous one.","Guard dispatch with `if (client.destroyed) recreate();`.","Sequence shutdown so in-flight dispatches complete before destroy() (use drain or await pending ops).","Add an onResponseError handler to receive the error gracefully instead of throwing."],"exampleFix":"// before\nawait client.destroy()\nclient.dispatch(opts, handler) // throws\n// after\nawait client.destroy()\nclient = new Client(url)\nclient.dispatch(opts, handler)","handlingStrategy":"type-guard","validationCode":"function dispatchOrRecreate(client, opts, handler) {\n  if (client.destroyed) {\n    client = new Client(client[kUrl]);\n  }\n  return client.dispatch(opts, handler);\n}","typeGuard":"!client.destroyed","tryCatchPattern":"try { client.dispatch(opts, handler); } catch (e) { if (e.code === 'UND_ERR_DESTROYED') { client = new Client(url); client.dispatch(opts, handler); } else throw e; }","preventionTips":["Never dispatch from a destroyed client; recreate it first.","Coordinate shutdown so destroy() runs after in-flight dispatches.","Implement onResponseError on handlers to absorb lifecycle errors gracefully."],"tags":["undici","dispatcher","lifecycle","destroyed","state-error"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}