{"record":{"id":"c22b661765446c88","repo":"siyuan-note/siyuan","slug":"obsidian-vault-is-unreadable-path-is-empty","errorCode":null,"errorMessage":"Obsidian Vault is unreadable: path is empty","messagePattern":"Obsidian Vault is unreadable: path is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/import_obsidian.go","lineNumber":560,"sourceCode":"\t\t\t}\n\t\t\tret.Analysis.Warnings = append(ret.Analysis.Warnings, asset.Source.RelPath)\n\t\t\tcontinue\n\t\t}\n\t\tret.ImportAssets[key] = asset\n\t\tret.Analysis.ImportableAssetCount++\n\t\tret.Analysis.ImportableAssetSize += asset.Source.Size\n\t}\n\tret.Analysis.UnreferencedFileCount = len(ret.ImportAssets) - len(ret.ReferencedAssets)\n\tif ret.Analysis.UnreferencedFileCount < 0 {\n\t\tret.Analysis.UnreferencedFileCount = 0\n\t}\n\tprogress(100, \"Analysis completed\")\n\treturn ret, nil\n}\n\nfunc validateObsidianVaultRoot(localPath string) (string, error) {\n\tif strings.TrimSpace(localPath) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: path is empty\", errObsidianVaultUnreadable)\n\t}\n\tabs, err := filepath.Abs(filepath.Clean(localPath))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: normalize Vault path: %v\", errObsidianVaultUnreadable, err)\n\t}\n\tinfo, err := os.Lstat(abs)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: read Vault root: %v\", errObsidianVaultUnreadable, err)\n\t}\n\tif !info.IsDir() {\n\t\treturn \"\", errObsidianVaultNotDirectory\n\t}\n\tif info.Mode()&os.ModeSymlink != 0 || isObsidianResolvedLink(abs) {\n\t\treturn \"\", fmt.Errorf(\"%w: Vault root is a symbolic link or reparse point\", errObsidianVaultUnsafePath)\n\t}\n\tif util.IsSensitivePath(abs) {\n\t\treturn \"\", fmt.Errorf(\"%w: selected Vault path is sensitive\", errObsidianVaultUnsafePath)\n\t}","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/import_obsidian.go#L542-L578","documentation":"A wrapped variant of errObsidianVaultUnreadable (line 559-560): returned by validateObsidianVaultRoot when the localPath argument, after trimming whitespace, is the empty string. This is the first guard in root validation, catching a missing or blank path before any filesystem access. It wraps the unreadable sentinel with the suffix ': path is empty'.","triggerScenarios":"POST /api/import/startObsidianVaultAnalysis with localPath set to \"\", a whitespace-only string, or null/undefined coerced to empty. The trim check at line 559 fires immediately.","commonSituations":"The frontend file picker returned no selection; the path field was left blank in a scripted API call; a null value was JSON-encoded as empty string; a UI bug submitted the form without a selected folder.","solutions":["Provide a non-empty directory path as localPath in the request body.","Validate on the client that the path field is non-empty before submitting.","Check the JSON request body includes a 'localPath' key with a real filesystem path.","If using the UI, ensure the folder picker completed successfully before clicking import."],"exampleFix":"// before\nPOST /api/import/startObsidianVaultAnalysis { \"localPath\": \"\" }\n// -> \"Obsidian Vault is unreadable: path is empty\"\n\n// after\nPOST /api/import/startObsidianVaultAnalysis { \"localPath\": \"/home/user/MyVault\" }","handlingStrategy":"validation","validationCode":"// Ensure a non-empty path before calling the API\nif strings.TrimSpace(localPath) == \"\" {\n    return errors.New(\"Vault path must not be empty\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := model.StartObsidianVaultAnalysis(localPath); err != nil {\n    if errors.Is(err, errObsidianVaultUnreadable) && strings.Contains(err.Error(), \"path is empty\") {\n        return errors.New(\"no Vault folder was provided; please select a folder\")\n    }\n}","preventionTips":["Validate the path field is non-empty on the client before submitting.","Ensure the folder picker returns a value before enabling the import button."],"tags":["obsidian","import","validation","filesystem","input-validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}