{"record":{"id":"a7d8a0049e1642fe","repo":"siyuan-note/siyuan","slug":"vault-paths-differ-only-by-letter-case-s-and","errorCode":null,"errorMessage":"Vault paths differ only by letter case [%s] and [%s]","messagePattern":"Vault paths differ only by letter case \\[(.+?)\\] and \\[(.+?)\\]","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/import_obsidian.go","lineNumber":655,"sourceCode":"\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err = scanObsidianVaultFiles(ctx, vault, rel, abs); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif !isObsidianImportableFileMode(entryInfo.Mode()) {\n\t\t\tvault.Analysis.SkippedSpecialCount++\n\t\t\tcontinue\n\t\t}\n\n\t\text := strings.ToLower(filepath.Ext(name))\n\t\tisMD := ext == \".md\"\n\t\tfile := &obsidianSourceFile{RelPath: rel, AbsPath: abs, Size: entryInfo.Size(), ModTime: entryInfo.ModTime(), IsMD: isMD}\n\t\tkey := obsidianPathKey(rel)\n\t\tif existing := vault.Files[key]; existing != nil && existing.RelPath != rel {\n\t\t\treturn fmt.Errorf(\"Vault paths differ only by letter case [%s] and [%s]\", existing.RelPath, rel)\n\t\t}\n\t\tvault.Files[key] = file\n\t\tif !isMD {\n\t\t\tfinalName := util.AssetName(util.FilterUploadFileName(filepath.Base(rel)), ast.NewNodeID())\n\t\t\tvault.Assets[key] = &obsidianAssetPlan{Source: file, FinalName: finalName}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc isObsidianImportableFileMode(mode fs.FileMode) bool {\n\treturn mode.IsRegular()\n}\n\nfunc isObsidianResolvedLink(p string) bool {\n\tresolved, err := filepath.EvalSymlinks(p)\n\treturn err == nil && !sameObsidianPath(filepath.Clean(p), filepath.Clean(resolved))\n}","sourceCodeStart":637,"sourceCodeEnd":673,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/import_obsidian.go#L637-L673","documentation":"Obsidian allows two vault paths that differ only in letter case (e.g. `Notes.md` and `notes.md`); SiYuan's import normalizes paths to a case-insensitive key, and when two distinct files map to the same key the import is aborted. This prevents silent overwrites or duplicate blocks once files are converted into SiYuan's tree, which cannot represent both names on a case-insensitive filesystem.","triggerScenarios":"scanObsidianVaultFiles finds a second file whose relative path lowercased equals an already-registered file's key but whose actual spelling differs, i.e. the vault genuinely contains both `Foo.md` and `foo.md` (or `Img.png`/`img.png`).","commonSituations":"Vaults moved between case-insensitive (macOS/Windows) and case-sensitive (Linux) filesystems; duplicate notes created with the same name differing in case; sync tools that merge such files into one directory.","solutions":["Rename one of the two conflicting files so their names differ by more than case (Obsidian will also warn about this)","Update any wikilinks pointing at the old name after renaming","Check the vault on a case-sensitive mount or via terminal to find all case-colliding pairs","Re-run the import after the vault is clean"],"exampleFix":"// before: vault contains both\nnotes/Setup.md\nnotes/setup.md\n\n// after: rename one file\nnotes/Setup.md\nnotes/setup-guide.md","handlingStrategy":"validation","validationCode":"function findCaseCollisions(files) {\n  const seen = new Map()\n  for (const f of files) {\n    const key = f.toLowerCase()\n    if (seen.has(key)) return [seen.get(key), f]\n    seen.set(key, f)\n  }\n  return null\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Audit the vault for names differing only by case (`find . | tr 'A-Z' 'a-z' | sort | uniq -d`)","Rename duplicates in Obsidian before importing","Be extra careful after moving vaults between macOS/Windows and Linux"],"tags":["go","filesystem","obsidian-import","case-sensitivity","duplicate-path"],"backgroundTag":"file-already-exists","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}