nexu-io/open-design · error · DeployError
Cloudflare Pages assets must be ${formatMib(CLOUDFLARE_PAGES
Error message
Cloudflare Pages assets must be ${formatMib(CLOUDFLARE_PAGES_ASSET_MAX_BYTES)} or smaller: ${file.file} is ${formatMib(data.length)}. What it means
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.
Source
Thrown at apps/daemon/src/deploy.ts:1054
async function getCloudflarePagesUploadToken(config: DeployConfig): Promise<string> {
const tokenResp = await fetch(cloudflarePagesProjectUrl(config, 'upload-token'), {
headers: cloudflareHeaders(config),
});
const tokenBody = await readCloudflareJson(tokenResp);
const jwt = tokenBody?.result?.jwt || tokenBody?.jwt;
if (!tokenResp.ok || tokenBody?.success === false || !jwt) {
throw cloudflareError(tokenBody, tokenResp.status, 'Cloudflare Pages upload token request failed.');
}
return jwt;
}
async function uploadCloudflarePagesAssets(uploadToken: string, files: DeployFile[]) {
const uniqueFiles = new Map<string, { hash: string; data: Buffer; contentType: string }>();
for (const file of files) {
const data = Buffer.from(file.data);
if (data.length > CLOUDFLARE_PAGES_ASSET_MAX_BYTES) {
throw new DeployError(
`Cloudflare Pages assets must be ${formatMib(CLOUDFLARE_PAGES_ASSET_MAX_BYTES)} or smaller: ${file.file} is ${formatMib(data.length)}.`,
400,
);
}
const hash = cloudflarePagesAssetHash({ ...file, data });
if (!uniqueFiles.has(hash)) {
uniqueFiles.set(hash, {
hash,
data,
contentType: file.contentType || 'application/octet-stream',
});
}
}
const hashes = Array.from(uniqueFiles.keys());
const missing = await cloudflarePagesMissingAssetHashes(uploadToken, hashes);
if (missing.length > 0) {
const missingFiles = missing.map((hash) => {
const file = uniqueFiles.get(hash);View on GitHub (pinned to 5be4028344)
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.
Example fix
// before: 40 MiB video shipped inline
files.push({ file: 'bg.mp4', data: bigVideoBuffer });
// after: host externally, reference by URL
files = files.filter((f) => f.file !== 'bg.mp4');
html = html.replace('bg.mp4', 'https://cdn.example.com/bg.mp4'); Defensive patterns
Strategy: validation
Validate before calling
import { CLOUDFLARE_PAGES_ASSET_MAX_BYTES } from './deploy.js';
function findOversizedAssets(files: DeployFile[]): DeployFile[] {
return files.filter((f) => Buffer.byteLength(f.data) > CLOUDFLARE_PAGES_ASSET_MAX_BYTES);
}
const oversize = findOversizedAssets(files);
if (oversize.length) throw new Error(`Oversized before upload: ${oversize.map((f) => f.file).join(', ')}`); Type guard
function isWithinAssetLimit(file: DeployFile): boolean {
return Buffer.byteLength(file.data) <= 25 * 1024 * 1024;
} Try / catch
try {
await uploadCloudflarePagesAssets(token, files);
} catch (err) {
if (err instanceof DeployError && err.status === 400 && /Cloudflare Pages assets must be/.test(err.message)) {
// identify and compress/exclude the named asset, then retry
} else throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cloudflare API token is required.
- Could not deploy referenced files (${parts.join('; ')}).
- Cloudflare account ID is required.
- Cloudflare zone is required for a custom domain.
- Select a valid Cloudflare domain for the custom domain.
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/99249a298d9dca8b.
Report an issue: GitHub.