n8n-io/n8n · warning

error.message

Error message

error.message

What it means

HTTP 400 with `error.message` body returned at binary-data.controller.ts:30 when `GET /binary-data` throws a `BadRequestError` from `validateBinaryDataId` or `setContentHeaders`. The literal message ('Missing binary data ID', 'Malformed binary data ID', 'Invalid binary data mode', or 'Content not viewable') is sent verbatim via `res.status(400).end(error.message)`.

Source

Thrown at packages/cli/src/controllers/binary-data.controller.ts:30

import { BadRequestError } from '@/errors/response-errors/bad-request.error';

@RestController('/binary-data')
export class BinaryDataController {
	constructor(private readonly binaryDataService: BinaryDataService) {}

	@Get('/')
	async get(
		_: Request,
		res: Response,
		@Query { id: binaryDataId, action, fileName, mimeType }: BinaryDataQueryDto,
	) {
		try {
			this.validateBinaryDataId(binaryDataId);
			await this.setContentHeaders(binaryDataId, action, res, fileName, mimeType);
			return await this.binaryDataService.getAsStream(binaryDataId);
		} catch (error) {
			if (error instanceof FileNotFoundError) return res.status(404).end();
			if (error instanceof BadRequestError) return res.status(400).end(error.message);
			else throw error;
		}
	}

	@Get('/signed', { skipAuth: true })
	async getSigned(_: Request, res: Response, @Query { token }: BinaryDataSignedQueryDto) {
		try {
			const binaryDataId = this.binaryDataService.validateSignedToken(token);
			this.validateBinaryDataId(binaryDataId);
			await this.setContentHeaders(binaryDataId, 'download', res);
			return await this.binaryDataService.getAsStream(binaryDataId);
		} catch (error) {
			if (error instanceof FileNotFoundError) return res.status(404).end();
			if (error instanceof BadRequestError || error instanceof JsonWebTokenError)
				return res.status(400).end(error.message);
			else throw error;
		}
	}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Send a well-formed `id` of shape `<mode>:<path>` where `<mode>` ∈ {filesystem, filesystem-v2, s3, azure, database}.
  2. For `action=view`, supply a MIME type in `ViewableMimeTypes` (json, common image/audio/video, text/* excluding html/svg).
  3. When the frontend constructs the URL, derive `id` from the execution's `binary` data rather than hand-assembling it.
  4. If storage mode was changed, re-run the execution so binary IDs use the new mode prefix.

Example fix

// before
GET /binary-data?id=abc&action=view
// 400 Malformed binary data ID

// after
GET /binary-data?id=filesystem:exec-123/data.json&action=download
Defensive patterns

Strategy: validation

Validate before calling

const STORED_MODES = ['filesystem','filesystem-v2','s3','azure','database'] as const;
function validBinaryId(id: string) {
  const i = id.indexOf(':');
  if (i === -1) return false;
  const mode = id.slice(0, i);
  const path = id.slice(i + 1);
  return STORED_MODES.includes(mode as any) && path !== '' && path !== '/' && path !== '//';
}
// guard the fetch: if (!validBinaryId(id)) throw new TypeError('bad id')

Type guard

const isStoredMode = (m: string): m is typeof STORED_MODES[number] =>
  ['filesystem','filesystem-v2','s3','azure','database'].includes(m);

const isValidBinaryId = (id: unknown): id is string =>
  typeof id === 'string' && id.includes(':') &&
  isStoredMode(id.slice(0, id.indexOf(':'))) &&
  !['','/','//'].includes(id.slice(id.indexOf(':') + 1));

Try / catch

try {
  await binaryController.get(...);
} catch (e) {
  if (e instanceof BadRequestError) {
    // surface e.message to the user; do not retry the same id
  }
}

Prevention

When it happens

Trigger: Calling `GET /binary-data?id=&action=view`, omitting `id`, using an `id` without a `:` separator, with an unknown storage mode prefix, or requesting `action=view` on a non-viewable MIME type. The frontend binary viewer typically hits this on malformed payloads.

Common situations: Manual/incorrect binary URL construction; MCP/external clients that build the `id` by hand; switching `N8N_DEFAULT_BINARY_DATA_MODE` so old `default:` IDs become invalid; viewing an unsupported MIME type.

Related errors


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