{"id":"1c081aeaaa443d03","repo":"sindresorhus/got","slug":"missing-hook-event-knownhookevent","errorCode":null,"errorMessage":"Missing hook event: ${knownHookEvent}","messagePattern":"Missing hook event: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"source/core/options.ts","lineNumber":2463,"sourceCode":"\t\t\tconst typedKnownHookEvent = knownHookEvent as keyof Hooks;\n\t\t\tconst hooks = value[typedKnownHookEvent];\n\n\t\t\tassertAny(`hooks.${knownHookEvent}`, [is.array, is.undefined], hooks);\n\n\t\t\tif (hooks) {\n\t\t\t\tfor (const hook of hooks) {\n\t\t\t\t\tassert.function(hook);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.#merging) {\n\t\t\t\tif (hooks) {\n\t\t\t\t\t// @ts-expect-error FIXME\n\t\t\t\t\tthis.#internals.hooks[typedKnownHookEvent].push(...hooks);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (!hooks) {\n\t\t\t\t\tthrow new Error(`Missing hook event: ${knownHookEvent}`);\n\t\t\t\t}\n\n\t\t\t\t// @ts-expect-error FIXME\n\t\t\t\tthis.#internals.hooks[knownHookEvent] = [...hooks];\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\tWhether redirect responses should be followed automatically.\n\n \tOptionally, pass a function to dynamically decide based on the response object.\n\n\tNote that if a `303` is sent by the server in response to any request type (`POST`, `DELETE`, etc.), Got will automatically request the resource pointed to in the location header via `GET`.\n\tThis is in accordance with [the spec](https://tools.ietf.org/html/rfc7231#section-6.4.4). You can optionally turn on this behavior also for other redirect codes - see `methodRewriting`.\n\tOn cross-origin redirects, Got strips `host`, `cookie`, `cookie2`, `authorization`, and `proxy-authorization`. When a redirect rewrites the request to `GET`, Got also strips request body headers. Use `hooks.beforeRedirect` for app-specific sensitive headers.\n\n\t@default true","sourceCodeStart":2445,"sourceCodeEnd":2481,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/options.ts#L2445-L2481","documentation":"Thrown by the `hooks` setter (in the non-merging code path, i.e. when setting hooks directly rather than via `got.extend`) when a hook event key is present in the object but its value is falsy/empty. When you assign `hooks` outright each event you list must be backed by an actual array of functions; an undefined/null entry is treated as a missing implementation.","triggerScenarios":"Calling `got(url, {hooks: {beforeRequest: undefined}})` or `{hooks: {beforeRequest: null}}` (or an empty value) directly on a request. Note: this does not fire for `got.extend({hooks: {...}})` merges, where undefined entries are tolerated.","commonSituations":"Conditionally building a hooks object where some keys end up undefined (e.g. `{beforeRequest: cond ? fn : undefined}`); spreading partial hook configs.","solutions":["Omit the key entirely instead of setting it to undefined/null: only include events that have a real array.","Build the hooks object conditionally so falsy entries are not inserted.","Default each event to an empty array `[]` if you must list the key."],"exampleFix":"// before\nconst hooks = {beforeRequest: useAuth ? authHook : undefined};\nawait got(url, {hooks});\n// after\nconst hooks = {};\nif (useAuth) hooks.beforeRequest = [authHook];\nawait got(url, {hooks});","handlingStrategy":"validation","validationCode":"function stripFalsyHooks(hooks) {\n  const out = {};\n  for (const [ev, fns] of Object.entries(hooks ?? {})) {\n    if (Array.isArray(fns) && fns.length > 0) out[ev] = fns;\n  }\n  return out;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build hook objects conditionally; do not insert keys with undefined values.","Prefer `got.extend({hooks: {...}})` (merging) if you need partial hook configs."],"tags":["options","hooks","validation","config"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}