laurent22/joplin · warning · JoplinError
downloadLimiter
downloadLimiter
Error message
${this.requestId}: Total bytes stored (${this.totalBytes_}) has exceeded the amount established (${this.maxTotalBytes}) What it means
A JoplinError (ErrorCode.DownloadLimiter) thrown by the totalBytes setter on LimitedDownloadController when the accumulated totalBytes_ has already reached or exceeded maxTotalBytes. It fires on the NEXT write attempt after the limit is hit — the setter checks the previous value before accepting the new one. handleChunk wires this so the in-flight download request is destroyed with the error, halting oversized downloads (used when fetching remote images/resources during sync or preview).
Source
Thrown at packages/lib/downloadController.ts:46
// counts before the downloaded has finished, so at the end if the totalBytes > maxTotalBytesAllowed
// it means that imageCount will be higher than the total downloaded during the process
private imagesCount_ = 0;
// how many images links the content has
private imageCountExpected_ = 0;
private requestId = '';
private maxTotalBytes = 0;
public readonly maxImagesCount: number;
public constructor(maxTotalBytes: number, maxImagesCount: number, requestId: string) {
this.maxTotalBytes = maxTotalBytes;
this.maxImagesCount = maxImagesCount;
this.requestId = requestId;
}
public set totalBytes(value: number) {
if (this.totalBytes_ >= this.maxTotalBytes) {
throw new JoplinError(`${this.requestId}: Total bytes stored (${this.totalBytes_}) has exceeded the amount established (${this.maxTotalBytes})`, ErrorCode.DownloadLimiter);
}
this.totalBytes_ = value;
}
public get totalBytes() {
return this.totalBytes_;
}
public set imagesCount(value: number) {
if (this.imagesCount_ > this.maxImagesCount) {
throw new JoplinError(`${this.requestId}: Total images to be stored (${this.imagesCount_}) has exceeded the amount established (${this.maxImagesCount})`, ErrorCode.DownloadLimiter);
}
this.imagesCount_ = value;
}
public get imagesCount() {
return this.imagesCount_;
}View on GitHub (pinned to 2654b33620)
Solutions
- Increase maxTotalBytes when constructing the LimitedDownloadController if large downloads are expected.
- Reduce the number/size of remote images in the content being synced/rendered.
- Handle ErrorCode.DownloadLimiter at the call site to degrade gracefully (skip the image, show a placeholder) instead of failing the whole operation.
- Investigate the source if a single resource unexpectedly exceeds the cap.
Example fix
// before
controller.totalBytes += chunk.length; // throws once cap exceeded
// after — handle the limit and destroy the request cleanly
try {
controller.totalBytes += chunk.length;
} catch (error) {
request.destroy(error);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check the remaining budget before starting a download
if (controller.totalBytes + expectedSize > controller.maxTotalBytes) {
// skip the download or raise the limit
return;
} Type guard
import JoplinError from './JoplinError';
import { ErrorCode } from './errors';
function isDownloadLimitError(e: unknown): e is JoplinError {
return e instanceof JoplinError && (e as any).code === ErrorCode.DownloadLimiter;
} Try / catch
try {
controller.totalBytes += chunk.length;
} catch (error) {
if (isDownloadLimitError(error)) {
request.destroy(error); // abort the HTTP download cleanly
return;
}
throw error;
} Prevention
- Size maxTotalBytes to the largest legitimate resource you expect to download.
- Use the handleChunk() helper so the request is destroyed automatically on limit breach.
- Catch ErrorCode.DownloadLimiter at the operation level to skip oversized items gracefully.
When it happens
Trigger: Streaming a remote resource (image, attachment) via a chunked download where the running byte total crosses maxTotalBytes. handleChunk's returned callback adds chunk.length to totalBytes; once totalBytes_ >= maxTotalBytes, the next chunk throws DownloadLimiter and request.destroy(error) aborts the HTTP request.
Common situations: Syncing a note whose embedded remote images together exceed the configured byte cap; a malicious or misconfigured server returning an oversized body; legitimate large attachments on a target with a low maxTotalBytes setting.
Related errors
- s3UploadFileFrom: file does not exist
- No item with ID ${itemId}
- Please specify the sync target path.
- Synchronisation is already in progress.
- Cannot initialise synchroniser.
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/6859bf4f1d7a332f.
Report an issue: GitHub.