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

  1. Always return the response object from afterResponse hooks — mutate it in place if you need to change headers or body.
  2. If you need to retry, return the call to the retry function (the second hook argument) instead of returning a value.
  3. 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

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


AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03). Data as JSON: /data/errors/572e5697189cd2f0.json. Report an issue: GitHub.