{"record":{"id":"0653435174745810","repo":"laurent22/joplin","slug":"cannot-find-unique-filename","errorCode":null,"errorMessage":"Cannot find unique filename","messagePattern":"Cannot find unique filename","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/lib/fs-driver-base.ts","lineNumber":227,"sourceCode":"\t\tconst nameNoExt = pathPrefix + filename(baseName);\n\t\tlet extension = fileExtension(baseName);\n\t\tif (extension) extension = `.${extension}`;\n\t\tlet nameToTry = nameNoExt + extension;\n\t\twhile (true) {\n\t\t\t// Check if the filename does not exist in the filesystem and is not reserved\n\t\t\tconst exists = await this.exists(nameToTry) || isReserved(nameToTry);\n\t\t\tif (!exists) return nameToTry;\n\t\t\tif (!markdownSafe) {\n\t\t\t\tnameToTry = `${nameNoExt} (${counter})${extension}`;\n\t\t\t} else {\n\t\t\t\tnameToTry = `${nameNoExt}-${counter}${extension}`;\n\t\t\t}\n\t\t\tcounter++;\n\t\t\tif (counter >= 1000) {\n\t\t\t\tnameToTry = `${nameNoExt} (${new Date().getTime()})${extension}`;\n\t\t\t\tawait time.msleep(10);\n\t\t\t}\n\t\t\tif (counter >= 1100) throw new Error('Cannot find unique filename');\n\t\t}\n\t}\n\n\tpublic async removeAllThatStartWith(dirPath: string, filenameStart: string) {\n\t\tif (!filenameStart || !dirPath) throw new Error('dirPath and filenameStart cannot be empty');\n\n\t\tconst stats = await this.readDirStats(dirPath);\n\n\t\tfor (const stat of stats) {\n\t\t\tif (stat.path.indexOf(filenameStart) === 0) {\n\t\t\t\tawait this.remove(`${dirPath}/${stat.path}`);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async waitTillExists(path: string, timeout = 10000) {\n\t\tconst startTime = Date.now();\n","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/fs-driver-base.ts#L209-L245","documentation":"Thrown by findUniqueFilename() in the base fs driver. It appends a counter (or, after 1000 tries, a timestamp) to generate a non-existent, non-reserved name. If after 1100 attempts every candidate still exists or is reserved, it gives up rather than loop infinitely.","triggerScenarios":"Calling findUniqueFilename for a directory containing thousands of files with the same base name and incrementing pattern, or with many reserved names colliding with the generated candidates.","commonSituations":"Exporting/importing thousands of notes with identical titles; a directory polluted with stale 'name (N).md' files from prior exports; reserved-name list overly broad and colliding; pathological filenames; a bug creating files faster than uniqueness can be found.","solutions":["Clear or archive the target directory so existing-name collisions drop below 1000.","Use a more distinctive base name (include a date or random component) before calling findUniqueFilename.","Review and trim the reservedNames list if it's catching legitimate candidates.","If you control the caller, fall back to a UUID-based name instead of the counter loop."],"exampleFix":"// before\nconst name = await shim.fsDriver().findUniqueFilename(dir, baseName);\n// after - prepend a unique stamp to avoid the 1100-try ceiling\nconst stamped = `${baseName}-${Date.now()}`;\nconst name = await shim.fsDriver().findUniqueFilename(dir, stamped);","handlingStrategy":"validation","validationCode":"// Cap how many colliding names exist in the target dir before generating.\nconst colliding = (await shim.fsDriver().readDirStats(dir)).filter(s => s.path.indexOf(baseName) === 0).length;\nif (colliding > 900) throw new Error(`Too many name collisions for ${baseName}; clear the directory.`);","typeGuard":"function isUniqueFilenameExhausted(e: any): boolean {\n  return e && typeof e.message === 'string' && e.message === 'Cannot find unique filename';\n}","tryCatchPattern":"let name;\ntry {\n  name = await shim.fsDriver().findUniqueFilename(dir, baseName);\n} catch (e) {\n  if (isUniqueFilenameExhausted(e)) {\n    name = `${dir}/${baseName}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`;\n  } else throw e;\n}","preventionTips":["Clear or archive directories before bulk exports to avoid thousands of collisions.","Use distinctive base names (include dates or IDs) when generating many files.","Prefer UUID-based names for programmatic bulk creation.","Trim the reservedNames list if it's overly broad."],"tags":["filesystem","filename","export","import"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}