HeyPuter/puter · warning · HttpError
conflict
conflict
Error message
Duplicate file content for batch index ${itemIndex} What it means
Thrown during multipart /fs/batchWrite when two file parts in the same request resolve to the same manifest item index. Each manifest item may be uploaded exactly once; the second part for an already-seen index is rejected with HTTP 409. The item index is resolved from the field name and the part order, so duplicate field names or a client bug re-sending a file triggers it.
Source
Thrown at src/backend/controllers/fs/FSController.ts:683
400,
'Batch write manifest is missing',
{ legacyCode: 'bad_request' },
);
}
const itemIndex = this.#resolveMultipartFileIndex(
fieldName,
currentFileOrder,
parsedManifest,
);
if (parsedManifest.ignoredItemIndexes.has(itemIndex)) {
if (!stream.readableEnded && !stream.destroyed) {
stream.resume();
}
return null;
}
if (uploadedIndexes.has(itemIndex)) {
throw new HttpError(
409,
`Duplicate file content for batch index ${itemIndex}`,
{ legacyCode: 'conflict' },
);
}
uploadedIndexes.add(itemIndex);
const preparedIndex =
preparedIndexByManifestIndex.get(itemIndex);
const preparedItem =
preparedIndex === undefined
? undefined
: preparedBatch.itemsByIndex.get(preparedIndex);
if (preparedIndex === undefined || !preparedItem) {
throw new HttpError(
400,
`Batch write metadata was not found for index ${itemIndex}`,
{ legacyCode: 'bad_request' },View on GitHub (pinned to 908ec23eda)
Solutions
- Ensure each manifest item index appears exactly once among the file parts.
- On retry, build a fresh FormData rather than appending to the previous one.
- Validate `uploadedIndexes`-equivalent state client-side before sending.
Example fix
// before
files.forEach((f, i) => fd.append(`file${i}`, f)); // if files contains dupes by index
// after
const seen = new Set();
files.forEach((f, i) => {
const idx = resolveIndex(f);
if (seen.has(idx)) return;
seen.add(idx);
fd.append(`file${idx}`, f);
}); Defensive patterns
Strategy: validation
Validate before calling
function dedupeIndexes(items) {
const seen = new Set();
return items.filter(i => {
if (seen.has(i.index)) return false;
seen.add(i.index); return true;
});
} Try / catch
try { await batchWrite(form); }
catch (e) {
if (e?.code === 'conflict' && /Duplicate file content/.test(e.message)) { /* rebuild form without dup index */ }
else throw e;
} Prevention
- Build the FormData from a deduplicated list keyed by manifest index.
- On retry, construct a fresh FormData rather than appending to the old one.
- Track sent indexes client-side to avoid re-sending.
When it happens
Trigger: Two multipart parts whose field names map to the same manifest index (e.g. two `file0` fields, or two parts whose order-position both resolve to index 0). A retry logic that re-appends a file without resetting state. A client that streams the same logical file twice under different field names that both parse to index 0.
Common situations: Frontend retry/resume code that re-appends a file part after an error. A form builder that duplicates file inputs. Manual curl invocations that include the same file twice.
Related errors
- Failed to resolve prepared batch item for index ${index}
- unauthorized
- not_found
- access_denied
- cannot_write_to_root
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/1e91ae8cd4e4b17d.
Report an issue: GitHub.