{"record":{"id":"a6a9b4bf704eb059","repo":"siyuan-note/siyuan","slug":"batch","errorCode":null,"errorMessage":"batch","messagePattern":"batch","errorType":"validation","errorClass":"Base64ImageSizeLimitError","httpStatus":null,"severity":"error","filePath":"app/src/protyle/upload/base64File.ts","lineNumber":33,"sourceCode":"        super(`Base64 image ${scope} size ${actualBytes} exceeds ${maxBytes} bytes`);\n        this.name = \"Base64ImageSizeLimitError\";\n    }\n}\n\nexport const isBase64ImageSizeLimitError = (error: unknown): error is Base64ImageSizeLimitError =>\n    error instanceof Base64ImageSizeLimitError;\n\nexport const assertBase64ImageItemSize = (actualBytes: number, maxBytes?: number) => {\n    const itemMaxBytes = Math.min(maxBytes ?? BASE64_IMAGE_ITEM_MAX_BYTES, BASE64_IMAGE_ITEM_MAX_BYTES);\n    if (actualBytes > itemMaxBytes) {\n        throw new Base64ImageSizeLimitError(\"item\", actualBytes, itemMaxBytes);\n    }\n};\n\nexport const addBase64ImageBatchSize = (currentBytes: number, fileBytes: number) => {\n    const totalBytes = currentBytes + fileBytes;\n    if (totalBytes > BASE64_IMAGE_BATCH_MAX_BYTES) {\n        throw new Base64ImageSizeLimitError(\"batch\", totalBytes, BASE64_IMAGE_BATCH_MAX_BYTES);\n    }\n    return totalBytes;\n};\n\nconst startsWith = (bytes: Uint8Array, signature: number[]) =>\n    signature.every((value, index) => bytes[index] === value);\n\nconst detectBase64ImageFormat = (bytes: Uint8Array): IBase64ImageFormat | undefined => {\n    if (startsWith(bytes, [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) {\n        return {extension: \"png\", mime: \"image/png\"};\n    }\n    if (startsWith(bytes, [0xFF, 0xD8, 0xFF])) {\n        return {extension: \"jpg\", mime: \"image/jpeg\"};\n    }\n    if (startsWith(bytes, [0x47, 0x49, 0x46, 0x38, 0x37, 0x61]) ||\n        startsWith(bytes, [0x47, 0x49, 0x46, 0x38, 0x39, 0x61])) {\n        return {extension: \"gif\", mime: \"image/gif\"};\n    }","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/app/src/protyle/upload/base64File.ts#L15-L51","documentation":"addBase64ImageBatchSize accumulates the byte size of base64 images queued for a single upload batch. When the running total (currentBytes + fileBytes) exceeds BASE64_IMAGE_BATCH_MAX_BYTES, it throws a Base64ImageSizeLimitError with kind \"batch\", meaning the whole batch would exceed the configured size limit. This protects the editor from oversized upload payloads that would fail or time out.","triggerScenarios":"Calling addBase64ImageBatchSize with (currentBytes, fileBytes) whose sum exceeds BASE64_IMAGE_BATCH_MAX_BYTES, e.g. repeatedly adding large base64-encoded images (pasted screenshots) until the cumulative batch bytes pass the cap.","commonSituations":"Users paste many or very large screenshots into the editor; a plugin adds multiple base64 images to one upload queue; the batch limit is lowered via configuration while old queued images remain.","solutions":["Split the image into a new batch: flush/start a new upload batch before adding this file, keeping each batch under BASE64_IMAGE_BATCH_MAX_BYTES","Catch Base64ImageSizeLimitError and surface a user-facing message telling them the batch exceeds the size limit and to upload fewer/smaller images at once","Check the incoming fileBytes against BASE64_IMAGE_BATCH_MAX_BYTES before enqueueing and reject images that alone exceed the limit","Compress or downscale the image before base64 encoding to reduce its byte size"],"exampleFix":"// before\nlet batchBytes = 0;\nimages.forEach(img => { batchBytes = addBase64ImageBatchSize(batchBytes, img.bytes); });\n// after\nlet batchBytes = 0;\nfor (const img of images) {\n  if (batchBytes + img.bytes > BASE64_IMAGE_BATCH_MAX_BYTES) {\n    await flushBatch(); // start a new batch\n    batchBytes = 0;\n  }\n  batchBytes = addBase64ImageBatchSize(batchBytes, img.bytes);\n}","handlingStrategy":"validation","validationCode":"function canAddToBatch(currentBytes, fileBytes) {\n  return currentBytes + fileBytes <= BASE64_IMAGE_BATCH_MAX_BYTES;\n}","typeGuard":"const isBase64ImageSizeLimitError = (e: unknown): e is Base64ImageSizeLimitError =>\n  e instanceof Base64ImageSizeLimitError && e.kind === \"batch\";","tryCatchPattern":"try {\n  totalBytes = addBase64ImageBatchSize(currentBytes, fileBytes);\n} catch (e) {\n  if (e instanceof Base64ImageSizeLimitError) {\n    startNewBatch(); // flush and continue with a fresh batch\n  } else { throw e; }\n}","preventionTips":["Check the sum against BASE64_IMAGE_BATCH_MAX_BYTES before calling","Compress/resize images before base64 encoding","Flush the batch as soon as it approaches the limit","Reject single images larger than the whole batch limit up front"],"tags":["upload","base64","size-limit"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}