sindresorhus/got · error · TypeError
The `afterResponse` hook returned an invalid value
Error message
The `afterResponse` hook returned an invalid value
What it means
Thrown at source/as-promise/index.ts:171 after each afterResponse hook resolves. The wrapper expects every hook to yield back a response-shaped object: a plain object with a numeric `statusCode` and a `body` property. If the hook returns undefined, null, a string, or an object missing those fields, got cannot continue processing and throws this TypeError. The check exists because hooks can either return the (possibly mutated) response directly or call the retry callback; returning anything else is a contract violation that would crash later code that reads response.statusCode.
Source
Thrown at source/as-promise/index.ts:171
if (!isSameOrigin(previousUrl, nextUrl) && !hasExplicitBody) {
options.clearBody();
}
}
}
}
// Remove any further hooks for that request, because we'll call them anyway.
// The loop continues. We don't want duplicates (asPromise recursion).
// Unless preserveHooks is true, in which case we keep the remaining hooks.
if (!preserveHooks) {
options.hooks.afterResponse = options.hooks.afterResponse.slice(0, index);
}
throw new RetryError(request);
}));
if (!(is.object(response) && is.number(response.statusCode) && 'body' in response)) {
throw new TypeError('The `afterResponse` hook returned an invalid value');
}
}
} catch (error: unknown) {
request._beforeError(normalizeError(error));
return;
}
globalResponse = response;
if (!isResponseOk(response)) {
request._beforeError(new HTTPError(response));
return;
}
request.destroy();
promiseSettled = true;
resolve(request.options.resolveBodyOnly ? response.body as T : response as unknown as T);
})();View on GitHub (pinned to e3924aa1e5)
Solutions
- Always return the response object from afterResponse hooks — mutate it in place if you need to change headers or body.
- If you need to retry, return the call to the retry function (the second hook argument) instead of returning a value.
- Add an explicit return type annotation `: Response | RequestPromise<Response>` so the TypeScript compiler catches missing returns.
Example fix
// before
hooks: {
afterResponse: [(response, retry) => {
if (response.statusCode === 401) {
retry({ headers: { authorization: refresh() } }); // missing return
}
// missing return on happy path
}]
}
// after
hooks: {
afterResponse: [(response, retry) => {
if (response.statusCode === 401) {
return retry({ headers: { authorization: refresh() } });
}
return response;
}]
} Defensive patterns
Strategy: validation
Validate before calling
// Validate hook shape before registering it.
function validateAfterResponseHook(hook) {
// Wrap to assert the return value at runtime.
return (response, retry) => {
const result = hook(response, retry);
const unwrap = (v) => {
if (v && typeof v.then === 'function') return v.then(unwrap);
if (v === undefined || v === null) {
throw new TypeError('afterResponse hook returned nothing — must return the response or call retry()');
}
if (typeof v.statusCode !== 'number' || !('body' in v)) {
throw new TypeError('afterResponse hook must return a response-shaped object');
}
return v;
};
return unwrap(result);
};
} Type guard
import type {Response, RequestPromise} from 'got';
function isResponseLike(v: unknown): v is Response {
return typeof v === 'object' && v !== null
&& typeof (v as any).statusCode === 'number'
&& 'body' in (v as any);
} Try / catch
try {
await got(url, { hooks: { afterResponse: [hook] } });
} catch (error) {
if (error instanceof TypeError && /afterResponse hook returned an invalid value/.test(error.message)) {
throw new Error('afterResponse hook contract violation: must return the response or retry()', { cause: error });
}
throw error;
} Prevention
- Always return the response object (or the retry() call result) from afterResponse hooks.
- Annotate hook types explicitly: `(response: Response, retry: (opts?) => RequestPromise<Response>) => Response | RequestPromise<Response>`.
- Add a unit test that drives the hook with a mock response and asserts the return shape.
When it happens
Trigger: An afterResponse hook that forgets to return (implicit undefined), returns `null` on some branch, returns a modified options object instead of the response, or returns a promise that resolves to a non-response value. Triggered on the first response after such a hook runs.
Common situations: Refactoring a hook to short-circuit on a status code and forgetting the return on the happy path; returning the parsed JSON body instead of the response object; migrating from got v11 where hook return semantics were looser; TypeScript users who typed the hook loosely (any) so the bug isn't caught at compile time.
Related errors
- beforeCache hook must return false or undefined. To modify t
- The `beforeError` hook must return an Error instance. Receiv
- ERR_RETRYING
- A retry listener has been attached already.
- The reassigned stream body must be readable. Ensure you prov
AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03).
Data as JSON: /data/errors/572e5697189cd2f0.json.
Report an issue: GitHub.