siyuan-note/siyuan · error · Base64ImageSizeLimitError

BASE64_IMAGE_SIZE_LIMIT

BASE64_IMAGE_SIZE_LIMIT

Error message

Base64 image item size ${actualBytes} exceeds ${itemMaxBytes} bytes

What it means

assertBase64ImageItemSize enforces a per-image byte limit when handling base64 images. The effective maximum is the caller-supplied maxBytes capped at BASE64_IMAGE_ITEM_MAX_BYTES. When the decoded image's byte size (actualBytes) exceeds that cap, a Base64ImageSizeLimitError (scope 'item', code BASE64_IMAGE_SIZE_LIMIT) is thrown with the message 'Base64 image item size ${actualBytes} exceeds ${itemMaxBytes} bytes'. It is called from createBase64ImageFile before constructing the File.

Source

Thrown at app/src/protyle/upload/base64File.ts:26

export type TBase64ImageSizeLimitScope = "item" | "batch";

export class Base64ImageSizeLimitError extends Error {
    readonly code = "BASE64_IMAGE_SIZE_LIMIT";

    constructor(readonly scope: TBase64ImageSizeLimitScope, readonly actualBytes: number, readonly maxBytes: number) {
        super(`Base64 image ${scope} size ${actualBytes} exceeds ${maxBytes} bytes`);
        this.name = "Base64ImageSizeLimitError";
    }
}

export const isBase64ImageSizeLimitError = (error: unknown): error is Base64ImageSizeLimitError =>
    error instanceof Base64ImageSizeLimitError;

export const assertBase64ImageItemSize = (actualBytes: number, maxBytes?: number) => {
    const itemMaxBytes = Math.min(maxBytes ?? BASE64_IMAGE_ITEM_MAX_BYTES, BASE64_IMAGE_ITEM_MAX_BYTES);
    if (actualBytes > itemMaxBytes) {
        throw new Base64ImageSizeLimitError("item", actualBytes, itemMaxBytes);
    }
};

export const addBase64ImageBatchSize = (currentBytes: number, fileBytes: number) => {
    const totalBytes = currentBytes + fileBytes;
    if (totalBytes > BASE64_IMAGE_BATCH_MAX_BYTES) {
        throw new Base64ImageSizeLimitError("batch", totalBytes, BASE64_IMAGE_BATCH_MAX_BYTES);
    }
    return totalBytes;
};

const startsWith = (bytes: Uint8Array, signature: number[]) =>
    signature.every((value, index) => bytes[index] === value);

const detectBase64ImageFormat = (bytes: Uint8Array): IBase64ImageFormat | undefined => {
    if (startsWith(bytes, [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) {
        return {extension: "png", mime: "image/png"};
    }

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Decode the base64 first and check its size with a helper (base64 length * 3/4 minus padding) before calling, then downscale/recompress the image if over the limit
  2. Compress the image (e.g. canvas.toBlob at lower quality or rescale dimensions) and retry with the smaller payload
  3. Raise the caller-provided maxBytes only up to BASE64_IMAGE_ITEM_MAX_BYTES if the limit was set too strictly for your workflow
  4. Catch Base64ImageSizeLimitError (or use isBase64ImageSizeLimitError) and surface a user-facing message asking for a smaller image

Example fix

// before: oversized base64 hits the limit
await createBase64ImageFile(dataUrl);
// after: pre-check and compress if needed
const bytes = estimateBase64Bytes(dataUrl);
if (bytes > BASE64_IMAGE_ITEM_MAX_BYTES) {
    dataUrl = await compressImage(dataUrl, BASE64_IMAGE_ITEM_MAX_BYTES);
}
await createBase64ImageFile(dataUrl);
Defensive patterns

Strategy: validation

Validate before calling

// estimate decoded byte size of a base64 data URL before calling
const estimateBase64Bytes = (dataUrl: string) => {
    const base64 = dataUrl.split(",")[1] || "";
    const padding = base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0;
    return Math.max(0, Math.floor(base64.length * 3 / 4) - padding);
};
if (estimateBase64Bytes(dataUrl) > BASE64_IMAGE_ITEM_MAX_BYTES) {
    // compress or reject before createBase64ImageFile
}

Type guard

import { isBase64ImageSizeLimitError } from "./base64File";
if (isBase64ImageSizeLimitError(err) && err.scope === "item") { /* handle per-item limit */ }

Try / catch

try {
    await createBase64ImageFile(dataUrl);
} catch (err) {
    if (isBase64ImageSizeLimitError(err)) {
        showToast(`Image too large: ${err.actualBytes} bytes (max ${err.maxBytes})`);
    } else { throw err; }
}

Prevention

When it happens

Trigger: Call createBase64ImageFile (or directly assertBase64ImageItemSize) with a base64 data URL whose decoded payload is larger than BASE64_IMAGE_ITEM_MAX_BYTES (or the caller's smaller maxBytes override).

Common situations: Pasting or dropping a very large screenshot/clipboard image that gets base64-encoded; a plugin or script uploading oversized images via the base64 path; tightened maxBytes overrides making previously acceptable images too large.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/f27ca79b9cb61985. Report an issue: GitHub.