{"record":{"id":"997b0ca7e0e63541","repo":"n8n-io/n8n","slug":"error-message-997b0c","errorCode":null,"errorMessage":"error.message","messagePattern":"error\\.message","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"packages/cli/src/controllers/binary-data.controller.ts","lineNumber":30,"sourceCode":"import { BadRequestError } from '@/errors/response-errors/bad-request.error';\n\n@RestController('/binary-data')\nexport class BinaryDataController {\n\tconstructor(private readonly binaryDataService: BinaryDataService) {}\n\n\t@Get('/')\n\tasync get(\n\t\t_: Request,\n\t\tres: Response,\n\t\t@Query { id: binaryDataId, action, fileName, mimeType }: BinaryDataQueryDto,\n\t) {\n\t\ttry {\n\t\t\tthis.validateBinaryDataId(binaryDataId);\n\t\t\tawait this.setContentHeaders(binaryDataId, action, res, fileName, mimeType);\n\t\t\treturn await this.binaryDataService.getAsStream(binaryDataId);\n\t\t} catch (error) {\n\t\t\tif (error instanceof FileNotFoundError) return res.status(404).end();\n\t\t\tif (error instanceof BadRequestError) return res.status(400).end(error.message);\n\t\t\telse throw error;\n\t\t}\n\t}\n\n\t@Get('/signed', { skipAuth: true })\n\tasync getSigned(_: Request, res: Response, @Query { token }: BinaryDataSignedQueryDto) {\n\t\ttry {\n\t\t\tconst binaryDataId = this.binaryDataService.validateSignedToken(token);\n\t\t\tthis.validateBinaryDataId(binaryDataId);\n\t\t\tawait this.setContentHeaders(binaryDataId, 'download', res);\n\t\t\treturn await this.binaryDataService.getAsStream(binaryDataId);\n\t\t} catch (error) {\n\t\t\tif (error instanceof FileNotFoundError) return res.status(404).end();\n\t\t\tif (error instanceof BadRequestError || error instanceof JsonWebTokenError)\n\t\t\t\treturn res.status(400).end(error.message);\n\t\t\telse throw error;\n\t\t}\n\t}","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/controllers/binary-data.controller.ts#L12-L48","documentation":"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)`.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Send a well-formed `id` of shape `<mode>:<path>` where `<mode>` ∈ {filesystem, filesystem-v2, s3, azure, database}.","For `action=view`, supply a MIME type in `ViewableMimeTypes` (json, common image/audio/video, text/* excluding html/svg).","When the frontend constructs the URL, derive `id` from the execution's `binary` data rather than hand-assembling it.","If storage mode was changed, re-run the execution so binary IDs use the new mode prefix."],"exampleFix":"// before\nGET /binary-data?id=abc&action=view\n// 400 Malformed binary data ID\n\n// after\nGET /binary-data?id=filesystem:exec-123/data.json&action=download","handlingStrategy":"validation","validationCode":"const STORED_MODES = ['filesystem','filesystem-v2','s3','azure','database'] as const;\nfunction validBinaryId(id: string) {\n  const i = id.indexOf(':');\n  if (i === -1) return false;\n  const mode = id.slice(0, i);\n  const path = id.slice(i + 1);\n  return STORED_MODES.includes(mode as any) && path !== '' && path !== '/' && path !== '//';\n}\n// guard the fetch: if (!validBinaryId(id)) throw new TypeError('bad id')","typeGuard":"const isStoredMode = (m: string): m is typeof STORED_MODES[number] =>\n  ['filesystem','filesystem-v2','s3','azure','database'].includes(m);\n\nconst isValidBinaryId = (id: unknown): id is string =>\n  typeof id === 'string' && id.includes(':') &&\n  isStoredMode(id.slice(0, id.indexOf(':'))) &&\n  !['','/','//'].includes(id.slice(id.indexOf(':') + 1));","tryCatchPattern":"try {\n  await binaryController.get(...);\n} catch (e) {\n  if (e instanceof BadRequestError) {\n    // surface e.message to the user; do not retry the same id\n  }\n}","preventionTips":["Always derive binary IDs from execution response payloads, never construct by hand.","After changing N8N_DEFAULT_BINARY_DATA_MODE, re-run executions so IDs use the new mode prefix.","Frontend should validate the id format before navigating to the binary URL."],"tags":["binary-data","rest","bad-request","validation"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}