n8n-io/n8n · error · ApiError

Request failed (${response.status})

Error message

Request failed (${response.status})

What it means

Thrown by N8nClient.request() when response.ok is false (status >= 400) AND the error response body lacks a recognizable 'message' field. The fallback message includes the raw status code. When the server returns a structured {message: '...'} body, that message is used instead — this fires only when the body is unstructured or non-JSON.

Source

Thrown at packages/@n8n/cli/src/client.ts:153

				`Connection error: ${msg}. Check the URL and ensure the instance is running.`,
			);
		}

		this.debug?.(`← ${response.status} ${response.statusText} (${Date.now() - start}ms)`);

		if (!response.ok) {
			const errorBody = await this.readBody(response);
			const message =
				typeof errorBody === 'object' && errorBody !== null && 'message' in errorBody
					? String((errorBody as Record<string, unknown>).message)
					: `Request failed (${response.status})`;
			const hint =
				response.status === 401
					? "Check your API key. Run 'n8n-cli config set-api-key <key>' or set N8N_API_KEY."
					: response.status === 404
						? 'Resource not found. Verify the ID is correct.'
						: undefined;
			throw new ApiError(response.status, message, hint, errorBody);
		}

		options.onResponse?.(response);

		if (response.status === 204) {
			return undefined as T;
		}

		if (options.responseType === 'binary') {
			return Buffer.from(await response.arrayBuffer()) as T;
		}

		return (await this.readBody(response)) as T;
	}

	private async readBody(response: Response): Promise<unknown> {
		const contentType = response.headers.get('content-type') ?? '';
		return contentType.includes('application/json') ? await response.json() : await response.text();

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Check ApiError.statusCode and ApiError.hint for guidance
  2. For 401: set a valid API key via 'n8n-cli config set-api-key <key>' or N8N_API_KEY
  3. For 404: verify the resource ID exists and the endpoint path is correct
  4. For 5xx: check the n8n server logs for the underlying error
  5. Inspect ApiError.details for the raw error body
Defensive patterns

Strategy: try-catch

Type guard

import { ApiError } from './client';

function isApiError(e: unknown): e is ApiError {
  return e instanceof ApiError;
}

Try / catch

try {
  return await client.getWorkflow(id);
} catch (e) {
  if (e instanceof ApiError) {
    switch (e.statusCode) {
      case 401: throw new Error('API key invalid. Run: n8n-cli config set-api-key <key>');
      case 404: throw new Error(`Workflow ${id} not found`);
      case 429: throw new Error('Rate limited. Retry later.');
      default: throw new Error(`API error ${e.statusCode}: ${e.message}`);
    }
  }
  throw e;
}

Prevention

When it happens

Trigger: Any API call returns 4xx/5xx with a non-JSON body or a JSON body without a message field: 500 with an HTML error page, 502/504 from a reverse proxy, 413 with empty body, 429 with a plain-text rate-limit notice.

Common situations: Invalid resource ID (404 but server returns no message), server crash (500 with HTML), rate limiting (429), API version mismatch, payload too large.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/cceaaf3fbeebb720. Report an issue: GitHub.