n8n-io/n8n · warning · BadRequestError

Missing binary data ID

Error message

Missing binary data ID

What it means

BadRequestError (HTTP 400) 'Missing binary data ID' thrown at binary-data.controller.ts:52 inside `validateBinaryDataId` when the `id` query param is falsy (empty/undefined). The route requires an `id` of shape `<mode>:<path>` before any storage lookup.

Source

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

	@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;
		}
	}

	private validateBinaryDataId(binaryDataId: string) {
		if (!binaryDataId) {
			throw new BadRequestError('Missing binary data ID');
		}

		const separatorIndex = binaryDataId.indexOf(':');

		if (separatorIndex === -1) {
			throw new BadRequestError('Malformed binary data ID');
		}

		const mode = binaryDataId.substring(0, separatorIndex);

		if (!isValidNonDefaultMode(mode)) {
			throw new BadRequestError('Invalid binary data mode');
		}

		const path = binaryDataId.substring(separatorIndex + 1);

		if (path === '' || path === '/' || path === '//') {
			throw new BadRequestError('Malformed binary data ID');

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Always include `?id=<mode>:<path>` in the request.
  2. Validate at the call site before issuing the request — see validationCode.
  3. Log the full request URL on 400 to catch clients that drop the param.

Example fix

// before
GET /binary-data?action=download
// 400 Missing binary data ID

// after
GET /binary-data?id=filesystem:exec-1/file.bin&action=download
Defensive patterns

Strategy: validation

Validate before calling

function requireBinaryId(id: unknown): asserts id is string {
  if (typeof id !== 'string' || id.length === 0) throw new TypeError('Missing binary data ID');
}
// call before building the request URL

Type guard

const hasBinaryId = (q: unknown): q is { id: string } =>
  typeof q === 'object' && q !== null && typeof (q as any).id === 'string' && (q as any).id.length > 0;

Try / catch

try { await get(req); } catch (e) { if (e instanceof BadRequestError && /Missing/.test(e.message)) {/* ask caller for id */} }

Prevention

When it happens

Trigger: Calling `GET /binary-data` or `GET /binary-data/signed`-derived flow without an `id`, with `id=`, or where the DTO coerced it to undefined.

Common situations: External/MCP clients omitting `id`; frontend bugs dropping the param; misconfigured reverse-proxy stripping query strings.

Related errors


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