{"record":{"id":"99249a298d9dca8b","repo":"nexu-io/open-design","slug":"cloudflare-pages-assets-must-be-formatmib-cloudf","errorCode":null,"errorMessage":"Cloudflare Pages assets must be ${formatMib(CLOUDFLARE_PAGES_ASSET_MAX_BYTES)} or smaller: ${file.file} is ${formatMib(data.length)}.","messagePattern":"Cloudflare Pages assets must be (.+?) or smaller: (.+?) is (.+?)\\.","errorType":"http","errorClass":"DeployError","httpStatus":400,"severity":"error","filePath":"apps/daemon/src/deploy.ts","lineNumber":1054,"sourceCode":"\nasync function getCloudflarePagesUploadToken(config: DeployConfig): Promise<string> {\n  const tokenResp = await fetch(cloudflarePagesProjectUrl(config, 'upload-token'), {\n    headers: cloudflareHeaders(config),\n  });\n  const tokenBody = await readCloudflareJson(tokenResp);\n  const jwt = tokenBody?.result?.jwt || tokenBody?.jwt;\n  if (!tokenResp.ok || tokenBody?.success === false || !jwt) {\n    throw cloudflareError(tokenBody, tokenResp.status, 'Cloudflare Pages upload token request failed.');\n  }\n  return jwt;\n}\n\nasync function uploadCloudflarePagesAssets(uploadToken: string, files: DeployFile[]) {\n  const uniqueFiles = new Map<string, { hash: string; data: Buffer; contentType: string }>();\n  for (const file of files) {\n    const data = Buffer.from(file.data);\n    if (data.length > CLOUDFLARE_PAGES_ASSET_MAX_BYTES) {\n      throw new DeployError(\n        `Cloudflare Pages assets must be ${formatMib(CLOUDFLARE_PAGES_ASSET_MAX_BYTES)} or smaller: ${file.file} is ${formatMib(data.length)}.`,\n        400,\n      );\n    }\n    const hash = cloudflarePagesAssetHash({ ...file, data });\n    if (!uniqueFiles.has(hash)) {\n      uniqueFiles.set(hash, {\n        hash,\n        data,\n        contentType: file.contentType || 'application/octet-stream',\n      });\n    }\n  }\n  const hashes = Array.from(uniqueFiles.keys());\n  const missing = await cloudflarePagesMissingAssetHashes(uploadToken, hashes);\n  if (missing.length > 0) {\n    const missingFiles = missing.map((hash) => {\n      const file = uniqueFiles.get(hash);","sourceCodeStart":1036,"sourceCodeEnd":1072,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/deploy.ts#L1036-L1072","documentation":"Cloudflare Pages rejects any single uploaded asset larger than 25 MiB (CLOUDFLARE_PAGES_ASSET_MAX_BYTES). The daemon enforces this client-side inside uploadCloudflarePagesAssets before talking to the upload API, naming the offending file and its measured size in the message.","triggerScenarios":"Deploying a project whose file set contains a binary over 25 MiB: an uncompressed background video, a large PDF, a font collection, or a vendored archive. The per-file size check at deploy.ts:1053 fires during the direct-upload asset staging loop.","commonSituations":"Generated design deck embeds a heavy media asset; unoptimized images slipped into the build; a minified bundle plus sourcemap crosses the line; vendored third-party asset that should live on a CDN.","solutions":["Compress, resize, or re-encode the named asset under 25 MiB.","Move large media to a CDN and reference it by URL so it is excluded from the deploy file set.","Exclude the offending asset from includeProjectFiles or the deploy plan."],"exampleFix":"// before: 40 MiB video shipped inline\nfiles.push({ file: 'bg.mp4', data: bigVideoBuffer });\n\n// after: host externally, reference by URL\nfiles = files.filter((f) => f.file !== 'bg.mp4');\nhtml = html.replace('bg.mp4', 'https://cdn.example.com/bg.mp4');","handlingStrategy":"validation","validationCode":"import { CLOUDFLARE_PAGES_ASSET_MAX_BYTES } from './deploy.js';\n\nfunction findOversizedAssets(files: DeployFile[]): DeployFile[] {\n  return files.filter((f) => Buffer.byteLength(f.data) > CLOUDFLARE_PAGES_ASSET_MAX_BYTES);\n}\n\nconst oversize = findOversizedAssets(files);\nif (oversize.length) throw new Error(`Oversized before upload: ${oversize.map((f) => f.file).join(', ')}`);","typeGuard":"function isWithinAssetLimit(file: DeployFile): boolean {\n  return Buffer.byteLength(file.data) <= 25 * 1024 * 1024;\n}","tryCatchPattern":"try {\n  await uploadCloudflarePagesAssets(token, files);\n} catch (err) {\n  if (err instanceof DeployError && err.status === 400 && /Cloudflare Pages assets must be/.test(err.message)) {\n    // identify and compress/exclude the named asset, then retry\n  } else throw err;\n}","preventionTips":["Run a deploy preflight that sums each asset's byte length against the 25 MiB limit.","Keep generated media on a CDN and reference by URL instead of inlining large binaries.","Compress images and re-encode video before they enter the deploy file set."],"tags":["cloudflare","deploy","assets","size-limit"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}