sindresorhus/got · error · TypeError

The `beforeError` hook must return an Error instance. Receiv

Error message

The `beforeError` hook must return an Error instance. Received ${is.string(error) ? 'string' : String(typeof error)}.

What it means

Thrown at source/core/index.ts:2512 inside the `_error` method's beforeError hook loop. Each beforeError hook is awaited and is expected to return a value that IS an Error (typically the same error, possibly enriched with context, or a wrapped RequestError). If a hook returns undefined, a string, an object, or any non-Error value, got throws this TypeError rather than continuing with a non-error and producing a confusing rejection later. The message reports the runtime type so you can spot the mistake quickly.

Source

Thrown at source/core/index.ts:2512

			throw error;
		}
	}

	private async _error(error: RequestError): Promise<void> {
		try {
			// Skip calling hooks for HTTP errors when throwHttpErrors is false (Promise API only).
			// See https://github.com/sindresorhus/got/issues/2103
			if (this.options && (!(error instanceof HTTPError) || this.options.throwHttpErrors)) {
				const hooks = this.options.hooks.beforeError;
				if (hooks.length > 0) {
					for (const hook of hooks) {
						// eslint-disable-next-line no-await-in-loop
						error = await hook(error) as RequestError;

						// Validate hook return value
						if (!(error instanceof Error)) {
							throw new TypeError(`The \`beforeError\` hook must return an Error instance. Received ${is.string(error) ? 'string' : String(typeof error)}.`);
						}
					}

					// Mark this error as processed by hooks so _destroy preserves custom error types.
					// Only mark non-RequestError errors, since RequestErrors are already preserved
					// by the instanceof check in _destroy (line 642).
					if (!(error instanceof RequestError)) {
						errorsProcessedByHooks.add(error);
					}
				}
			}
		} catch (error_: unknown) {
			const normalizedError = normalizeError(error_);
			error = new RequestError(normalizedError.message, normalizedError, this);
		}

		// Publish error event
		publishError({

View on GitHub (pinned to e3924aa1e5)

Solutions

  1. Always return the (possibly transformed) error from beforeError hooks — `return error;` at minimum.
  2. If you wrap the error, instantiate a real Error subclass: `return new RequestError('...', error, options)` or `return new MyError(message, { cause: error })`.
  3. Add a TypeScript return type annotation `: Error` on the hook so the compiler flags missing returns.

Example fix

// before
hooks: {
  beforeError: [error => { log(error); /* missing return */ }]
}

// after — always return an Error
hooks: {
  beforeError: [error => { log(error); return error; }]
}

// wrapping
hooks: {
  beforeError: [error => new RequestError(`upstream failed: ${error.message}`, error, error.request)]
}
Defensive patterns

Strategy: validation

Validate before calling

// Wrap beforeError hooks to guarantee they return an Error.
function wrapBeforeError(hook) {
  return async (error) => {
    const next = await hook(error);
    if (!(next instanceof Error)) {
      throw new TypeError(`beforeError hook must return an Error instance; received ${typeof next}`);
    }
    return next;
  };
}
options.hooks.beforeError = (options.hooks.beforeError ?? []).map(wrapBeforeError);

Type guard

function isErrorInstance(v: unknown): v is Error {
  return v instanceof Error;
}

Try / catch

try {
  await got(url, { hooks: { beforeError: [hook] } });
} catch (error) {
  if (error instanceof TypeError && /beforeError.*hook must return an Error/.test(error.message)) {
    throw new Error('beforeError hook contract violation — make sure the hook returns an Error', { cause: error });
  }
  throw error;
}

Prevention

When it happens

Trigger: A beforeError hook that logs and forgets to return the error; returns a string message; returns a plain `{ message }` object; returns `null` to swallow the error.

Common situations: Logging/metrics hooks that forget `return error`; refactoring a hook to branch and missing a return on one path; converting errors to a domain-specific shape using a plain object instead of an Error subclass.

Related errors


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