schollz/croc · error
Duplicate filename: ${name}
Error message
Duplicate filename: ${name} What it means
Stored manifests are flat (no directory structure), so prepareStoredFiles() normalizes each name with normalizeOutgoingFileName and rejects any second file that normalizes to an already-seen name. Two different inputs (a/report.pdf and b/report.pdf, or names that differ only in characters the normalizer strips) collide and throw.
Source
Thrown at web/src/protocol/stored.ts:309
settings: StoredSettings,
callbacks: { onStatus?(status: string): void } = {},
signal?: AbortSignal,
) {
if (selected.length === 0) throw new Error("Choose at least one file");
if (selected.length > settings.maxFiles) {
throw new Error(`Stored transfers can contain at most ${settings.maxFiles} files`);
}
const total = selected.reduce((sum, file) => sum + file.size, 0);
if (!Number.isSafeInteger(total) || total > settings.maxTransferBytes) {
throw new Error(`Stored transfer exceeds the ${settings.maxTransferBytes} byte limit`);
}
const names = new Set<string>();
const prepared: StoredPreparedFile[] = [];
let firstChunk = 0;
for (let index = 0; index < selected.length; index += 1) {
const file = selected[index];
const name = normalizeOutgoingFileName(file.name);
if (names.has(name)) throw new Error(`Duplicate filename: ${name}`);
names.add(name);
callbacks.onStatus?.(`Hashing ${index + 1}/${selected.length}: ${name}`);
const chunkCount = Math.ceil(file.size / storedChunkSize);
prepared.push({
file,
name,
size: file.size,
hash: new Uint8Array(),
sha256: await sha256Blob(file, signal),
modified: new Date(file.lastModified).toISOString(),
firstChunk,
chunkCount,
});
firstChunk += chunkCount;
}
return prepared;
}
View on GitHub (pinned to e25f1bdc04)
Solutions
- Rename one of the colliding files before selecting, or move them into a single folder with unique names
- Send folders via the direct (relay) transfer mode, which preserves structure, instead of stored mode
- Pre-scan the selection for post-normalization duplicates and surface them in the UI before prepareStoredFiles runs
Example fix
// pre-flight duplicate check
const seen = new Set<string>();
for (const f of selected) {
const name = normalizeOutgoingFileName(f.name);
if (seen.has(name)) throw new Error(`Duplicate filename: ${name}`);
seen.add(name);
} Defensive patterns
Strategy: validation
Validate before calling
const seen = new Set<string>();
for (const f of selected) { const n = normalizeOutgoingFileName(f.name); if (seen.has(n)) { showError(`Duplicate filename: ${n}`); return; } seen.add(n); } Prevention
- Warn when a multi-folder selection contains equal basenames
- Use direct relay transfer when folder structure must be preserved; stored transfers flatten it
When it happens
Trigger: Selecting two files with the same basename from different folders; names that are distinct on disk but identical after normalization (case folding, reserved-character stripping, or path removal).
Common situations: Users selecting multiple folders each containing README or invoice.pdf; case-insensitive filesystems where Photo.jpg and photo.jpg coexist but would collide on download targets.
Related errors
- Invalid stored-transfer id
- Stored transfers can contain at most ${settings.maxFiles} fi
- Stored transfer exceeds the ${settings.maxTransferBytes} byt
- Storage service returned an invalid download count
- Stored-transfer downloads must be a positive integer
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/a27c7bef7aa0b689.
Report an issue: GitHub.