sindresorhus/got · error · Error
Unexpected timeout option: ${key}
Error message
Unexpected timeout option: ${key} What it means
Thrown by the `timeout` setter when the `timeout` object has a key that is not one of the supported request phases: `lookup`, `connect`, `secureConnect`, `socket`, `send`, `response`, `read`, `request`. Each timeout bounds a specific lifecycle phase, so unknown phase names are rejected to avoid silently not applying a timeout.
Source
Thrown at source/core/options.ts:1862
- `send` starts when the socket is connected and ends with the request has been written to the socket.
- `request` starts when the request is initiated and ends when the response's end event fires.
*/
get timeout(): Delays {
// We always return `Delays` here.
// It has to be `Delays | number`, otherwise TypeScript will error because the getter and the setter have incompatible types.
return this.#internals.timeout;
}
set timeout(value: Delays) {
assertPlainObject('timeout', value);
for (const key of Object.keys(value)) {
if (key === '__proto__') {
continue;
}
if (!(key in this.#internals.timeout)) {
throw new Error(`Unexpected timeout option: ${key}`);
}
// @ts-expect-error - No idea why `value[key]` doesn't work here.
assertAny(`timeout.${key}`, [is.number, is.undefined], value[key]);
}
if (this.#merging) {
safeObjectAssign(this.#internals.timeout, value);
} else {
this.#internals.timeout = {...value};
}
}
/**
When specified, `prefixUrl` will be prepended to relative string `url` input.
The prefix can be any valid URL, either relative or absolute.
A trailing slash `/` is optional - one will be added automatically.
View on GitHub (pinned to e3924aa1e5)
Solutions
- Use only documented phase keys: `lookup`, `connect`, `secureConnect`, `socket`, `send`, `response`, `read`, `request`.
- For a whole-request timeout use `{timeout: {request: 5000}}`.
- Check the `${key}` in the message and rename/remove it.
Example fix
// before
await got(url, {timeout: {total: 5000}});
// after
await got(url, {timeout: {request: 5000}}); Defensive patterns
Strategy: type-guard
Validate before calling
const validPhases = new Set(['lookup','connect','secureConnect','socket','send','response','read','request']);
function validateTimeout(timeout) {
for (const key of Object.keys(timeout ?? {})) {
if (!validPhases.has(key)) throw new Error(`Unknown timeout phase: ${key}`);
}
} Type guard
import type {Delays} from 'got';
function isDelays(v: unknown): v is Delays {
if (typeof v !== 'object' || v === null) return false;
return Object.keys(v).every(k => ['lookup','connect','secureConnect','socket','send','response','read','request','__proto__'].includes(k));
} Prevention
- Use the `Delays` type from Got so the compiler rejects bad keys.
- Remember Got v13+ requires an object, not a bare number.
- Use `{request: ms}` for a whole-request cap.
When it happens
Trigger: Calling `got(url, {timeout: {headers: 5000}})` (no such phase), `{timeout: {total: 5000}}` (use `request` for the whole request), or any timeout object key outside the documented phases. Note Got v13+ removed the bare-number form, so `{timeout: 5000}` also fails type validation.
Common situations: Migrating from older Got where `timeout` could be a number or had different phase names; copying timeout config from another library; typos like `conect`.
Related errors
- Unexpected option: ${key}
- Unexpected agent option: ${key}
- Unexpected hook event: ${knownHookEvent}
- Missing hook event: ${knownHookEvent}
- Invalid DNS lookup IP version: ${value as string}
AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03).
Data as JSON: /data/errors/a5a6562df4b93758.json.
Report an issue: GitHub.