{"record":{"id":"1e70f9caf498643e","repo":"payloadcms/payload","slug":"file-data-must-be-valid-base64","errorCode":null,"errorMessage":"File data must be valid base64.","messagePattern":"File data must be valid base64\\.","errorType":"validation","errorClass":"APIError","httpStatus":400,"severity":"error","filePath":"packages/plugin-mcp/src/mcp/builtin/collections/fileInput.ts","lineNumber":135,"sourceCode":"        externalFileHeaderFilter: uploadConfig.externalFileHeaderFilter ?? (() => ({})),\n      },\n    })\n    file.mimetype = file.mimetype?.split(';')[0] || 'application/octet-stream'\n    file.size = file.data.length\n  }\n\n  if (maxFileSize !== undefined && Number.isFinite(maxFileSize) && file.size > maxFileSize) {\n    throw new APIError(`File exceeds the ${maxFileSize} byte upload limit.`, 400)\n  }\n\n  return file\n}\n\nfunction decodeBase64({ maxFileSize, value }: { maxFileSize?: number; value: string }): Buffer {\n  const normalized = value.replace(/\\s/g, '')\n\n  if (!/^[a-z0-9+/]*={0,2}$/i.test(normalized) || normalized.length % 4 === 1) {\n    throw new APIError('File data must be valid base64.', 400)\n  }\n\n  if (maxFileSize !== undefined && Number.isFinite(maxFileSize)) {\n    const paddingLength = normalized.endsWith('==') ? 2 : normalized.endsWith('=') ? 1 : 0\n    const decodedSize = Math.floor((normalized.length * 3) / 4) - paddingLength\n\n    if (decodedSize > maxFileSize) {\n      throw new APIError(`File exceeds the ${maxFileSize} byte upload limit.`, 400)\n    }\n  }\n\n  const data = Buffer.from(normalized, 'base64')\n\n  if (data.toString('base64').replace(/=+$/, '') !== normalized.replace(/=+$/, '')) {\n    throw new APIError('File data must be valid base64.', 400)\n  }\n\n  return data","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/plugin-mcp/src/mcp/builtin/collections/fileInput.ts#L117-L153","documentation":"Thrown as a 400 inside `decodeBase64` when the input fails the format guard — the regex `^[a-z0-9+/]*={0,2}$` (case-insensitive) does not match, or the length modulo 4 is 1 (an impossible base64 length). This catches obvious non-base64 strings before any decoding attempt.","triggerScenarios":"Passing a data-URL-prefixed string like `data:image/png;base64,...` as `source: 'base64'` `data`; passing raw binary or UTF-8 text; passing hex-encoded bytes; a string whose length % 4 === 1.","commonSituations":"Client reusing an `<img src=\"data:...\">` value verbatim; forgetting to strip the base64 prefix; encoding with a non-standard alphabet (URL-safe base64 with `-`/`_`); truncation that leaves an invalid length.","solutions":["Strip any `data:...;base64,` prefix before passing the value","Use standard base64 encoding (A–Z, a–z, 0–9, +, /) with 0–2 `=` padding characters","For URL-safe base64, convert `-`→`+` and `_`→`/` and add padding before sending"],"exampleFix":"// before\ndata: 'data:image/png;base64,iVBORw0KGgo='\n// after\nconst raw = 'iVBORw0KGgo='\nnew FileInput({ source: 'base64', name: 'x.png', mimeType: 'image/png', data: raw })","handlingStrategy":"validation","validationCode":"// Reject obviously non-base64 input before calling the tool\nfunction assertBase64(v: string) {\n  const norm = v.replace(/\\s/g, '')\n  if (!/^[a-z0-9+/]*={0,2}$/i.test(norm) || norm.length % 4 === 1)\n    throw new Error('value is not valid base64 — strip data: prefix and use standard alphabet')\n}","typeGuard":"function looksLikeBase64(v: string): boolean {\n  const n = v.replace(/\\s/g, '')\n  return /^[a-z0-9+/]*={0,2}$/i.test(n) && n.length % 4 !== 1\n}","tryCatchPattern":"import { APIError } from 'payload'\ntry {\n  await tool.call({ source: 'base64', data })\n} catch (e) {\n  if (e instanceof APIError && e.statusCode === 400 && /must be valid base64/.test(e.message)) {\n    // re-encode the source bytes canonically and retry\n  }\n  throw e\n}","preventionTips":["Always strip `data:<mime>;base64,` prefixes before sending","Use standard base64 (not URL-safe) and add correct `=` padding","Generate base64 with a trusted encoder rather than hand-editing"],"tags":["mcp","file-upload","base64","validation"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}