{"record":{"id":"2b94d9a99ad22364","repo":"mastra-ai/mastra","slug":"metadata-avatarurl-exceeds-avatar-max-bytes-byt","errorCode":null,"errorMessage":"metadata.avatarUrl exceeds ${AVATAR_MAX_BYTES}-byte limit (got ${byteLength})","messagePattern":"metadata\\.avatarUrl exceeds (.+?)-byte limit \\(got (.+?)\\)","errorType":"http","errorClass":"HTTPException","httpStatus":413,"severity":"error","filePath":"packages/server/src/server/handlers/validate-avatar.ts","lineNumber":43,"sourceCode":"  // `Buffer.from(..., 'base64')` decodes leniently — it silently ignores\n  // invalid characters and never throws. Validate the payload format strictly\n  // before measuring its byte length so malformed input is rejected.\n  const base64Payload = match[2]!;\n  const isStrictBase64 =\n    base64Payload.length > 0 &&\n    base64Payload.length % 4 === 0 &&\n    /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(base64Payload);\n  if (!isStrictBase64) {\n    throw new HTTPException(400, { message: 'metadata.avatarUrl contains invalid base64' });\n  }\n  const byteLength = Buffer.from(base64Payload, 'base64').byteLength;\n\n  if (byteLength === 0) {\n    throw new HTTPException(400, { message: 'metadata.avatarUrl is empty' });\n  }\n\n  if (byteLength > AVATAR_MAX_BYTES) {\n    throw new HTTPException(413, {\n      message: `metadata.avatarUrl exceeds ${AVATAR_MAX_BYTES}-byte limit (got ${byteLength})`,\n    });\n  }\n}\n","sourceCodeStart":25,"sourceCodeEnd":48,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/validate-avatar.ts#L25-L48","documentation":"HTTP 413 (Payload Too Large) from validateMetadataAvatarUrl: the decoded avatar exceeds AVATAR_MAX_BYTES. The message reports the limit and the actual decoded byte length, so callers can size their payload accordingly.","triggerScenarios":"POST/PUT to agent create/update routes with a base64 avatar whose decoded size exceeds AVATAR_MAX_BYTES (e.g. uploading multi-MB photos).","commonSituations":"Users picking high-resolution photos as avatars from an unresized file input; PNG screenshots instead of compressed JPEGs; forgetting base64 inflates size ~33% over raw bytes.","solutions":["Resize/compress the image client-side (e.g. canvas resize, JPEG quality ~0.8) until under AVATAR_MAX_BYTES decoded bytes.","Check the decoded size before submitting: Buffer.from(base64Payload, 'base64').byteLength.","Host large images externally and reference them via a non-avatarUrl metadata key if supported."],"exampleFix":"// before\nconst avatarUrl = 'data:image/png;base64,' + originalPhotoBase64; // decodes to ~4MB\n// after\nconst small = await resizeToDataUrl(file, { maxWidth: 256, mime: 'image/jpeg', quality: 0.8 });\nmetadata: { avatarUrl: small }","handlingStrategy":"validation","validationCode":"const AVATAR_MAX_BYTES = 200 * 1024; // check your server's limit\nconst bytes = Buffer.from((metadata.avatarUrl ?? '').split(',')[1] ?? '', 'base64').byteLength;\nif (bytes > AVATAR_MAX_BYTES) {\n  metadata.avatarUrl = await downscaleToDataUrl(metadata.rawAvatar, AVATAR_MAX_BYTES);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await saveAgent({ metadata });\n} catch (e) {\n  if (e instanceof HTTPException && e.status === 413) {\n    const limit = parseLimitFromMessage(e.message);\n    metadata.avatarUrl = await downscaleToDataUrl(metadata.rawAvatar, limit);\n    await saveAgent({ metadata });\n  } else throw e;\n}","preventionTips":["Resize avatars client-side (e.g. 256x256 JPEG) before upload.","Check decoded byte length before sending; base64 inflates size ~33%.","Surface the AVATAR_MAX_BYTES limit in the upload UI."],"tags":["http-413","payload-too-large","metadata","validation"],"backgroundTag":"payload-too-large","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}