laurent22/joplin · error · Error
Batch delete failed? ${JSON.stringify(check)}
Error message
Batch delete failed? ${JSON.stringify(check)} What it means
Thrown by the Dropbox driver while polling files/delete_batch/check. The loop accepts only 'complete' (success) and 'in_progress' (keep waiting); any other '.tag' (notably 'failed') aborts with the raw check response JSON. It surfaces Dropbox-side failures of a bulk delete job that the API reports asynchronously.
Source
Thrown at packages/lib/file-api-driver-dropbox.js:248
}
async clearRoot() {
const entries = await this.list('');
const batchDelete = [];
for (let i = 0; i < entries.items.length; i++) {
batchDelete.push({ path: this.makePath_(entries.items[i].path) });
}
const response = await this.api().exec('POST', 'files/delete_batch', { entries: batchDelete });
const jobId = response.async_job_id;
while (true) {
const check = await this.api().exec('POST', 'files/delete_batch/check', { async_job_id: jobId });
if (check['.tag'] === 'complete') break;
// It returns "failed" if it didn't work but anyway throw an error if it's anything other than complete or in_progress
if (check['.tag'] !== 'in_progress') {
throw new Error(`Batch delete failed? ${JSON.stringify(check)}`);
}
await time.sleep(2);
}
}
}
module.exports = { FileApiDriverDropbox };
View on GitHub (pinned to 2654b33620)
Solutions
- Inspect the JSON in the message — the check response contains a 'failures' array naming which entries errored and why; fix or remove those paths and retry.
- Verify the Dropbox app has files.content.delete scope and the account still authorizes the app (re-link the sync target).
- Reduce batch size or pre-filter paths that no longer exist before calling delete.
- Retry the sync — transient 'failed' tags from rate limiting often clear on the next run.
Example fix
// before
await driver.deleteMany(paths);
// after - pre-filter existing paths and surface partial failures
const existing = [];
for (const p of paths) {
if (await driver.stat(p)) existing.push(p);
}
// wrap call and, on failure, log check.failures for granular handling
try { await driver.deleteMany(existing); }
catch (e) { if (/Batch delete failed/.test(e.message)) logger.error('Dropbox partial:', e.message); throw e; } Defensive patterns
Strategy: retry
Validate before calling
// Verify paths exist and the job hasn't already failed before relying on the batch.
const valid = [];
for (const p of paths) { if (await driver.stat(p)) valid.push(p); }
if (!valid.length) return; // nothing to delete Type guard
function isDropboxBatchFailed(check: any): check is { '.tag': 'failed'; failures?: any[] } {
return check && check['.tag'] === 'failed';
} Try / catch
try {
await driver.deleteMany(paths);
} catch (error) {
const m = error.message.match(/Batch delete failed\? (.*)/s);
if (m) {
const check = JSON.parse(m[1]);
if (isDropboxBatchFailed(check) && check.failures?.length) {
// retry only the non-failed entries, or report partial
}
}
throw error;
} Prevention
- Pre-filter paths via stat() to avoid batching non-existent entries.
- Keep batch sizes moderate to reduce partial-failure blast radius.
- Log the full check response so failures are diagnosable.
- Confirm the Dropbox app retains files.content.delete scope before large syncs.
When it happens
Trigger: Calling this.delete() or clearRoot() with many paths so the driver dispatches files/delete_batch, then polling the job. Dropbox returns check['.tag'] === 'failed' (or any tag other than complete/in_progress) — e.g. a path inside the batch is missing, permission-denied, rate-limited, or the job hit an internal error.
Common situations: One entry in the batch references a non-existent path; Dropbox API quota/rate limiting; app permissions revoked mid-sync; transient Dropbox backend error; very large batch where a subset of entries fails.
Related errors
- uploadBlob: ${method} ${url}: ${error.toString()}
- AWS S3 bucket not found: ${SyncTargetAmazonS3.s3BucketName()
- User is not authenticated
- Could not access data on server "${options.path()}"
- WebDAV directory not found: ${options.path()}
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/850f88da4f9b7842.
Report an issue: GitHub.