siyuan-note/siyuan · error · obsidianUserError
read referenced attachment
Error message
read referenced attachment [%s]: %w
What it means
During Obsidian asset collection, validateObsidianReadableFile failed for an asset that is referenced by notes, so the import aborts with a wrapped error ('read referenced attachment [%s]: %w') carrying the i18n 348 message ('Unable to import asset file [%s]') plus the underlying cause. Unreferenced assets only produce a warning instead.
Solutions
- Open the reported attachment path in Obsidian/file manager to confirm it exists and is readable, then re-run the import
- Fix OS-level causes: download cloud-placeholder files, grant read permission, shorten the path
- Remove or repair the broken link in the note if the attachment is truly gone, then re-import
- If the file is intentionally absent, mark it as unreferenced (remove references) so the import degrades to a warning
Defensive patterns
Strategy: validation
Validate before calling
for (const a of referencedAssets) {
await fs.promises.access(a.path, fs.constants.R_OK).catch(() => { preflightFailures.push(a.relPath); });
}
if (preflightFailures.length) reportAndFix(preflightFailures); Try / catch
try { await importVault(path); } catch (e) { const m = /read referenced attachment \[(.+?)\]/.exec(String(e)); if (m) fixOrUnreferenceAsset(m[1]); else throw e; } Prevention
- Preflight-check every referenced attachment for readability before importing
- Fully download cloud-placeholder (OneDrive/iCloud) files first
- Repair or remove broken attachment links in Obsidian before import
When it happens
Trigger: Running the vault import when a note-referenced attachment cannot be opened/read: file deleted or moved since analysis, permission denied, name too long, locked by another process, or invalid characters in the path.
Common situations: Vault synced incompletely (empty attachment stubs), OneDrive/ iCloud placeholder files not downloaded, Windows permission or path-length issues, attachments excluded by sync tools.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/6522fb9cf1084f56.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/import_obsidian.go:541
progress(35, "Analyzing Markdown syntax")
if err = analyzeObsidianDocuments(ctx, ret, progress); err != nil {
return nil, err
}
ret.Analysis.MarkdownCount = countObsidianSourceDocs(ret.Docs)
var assetKeys []string
for key := range ret.Assets {
assetKeys = append(assetKeys, key)
}
sort.Strings(assetKeys)
for _, key := range assetKeys {
if err = ctx.Err(); err != nil {
return nil, err
}
asset := ret.Assets[key]
if err = validateObsidianReadableFile(asset.Source); err != nil {
if ret.ReferencedAssets[key] != nil {
return nil, newObsidianUserError(348, asset.Source.RelPath,
fmt.Errorf("read referenced attachment [%s]: %w", asset.Source.RelPath, err))
}
ret.Analysis.Warnings = append(ret.Analysis.Warnings, asset.Source.RelPath)
continue
}
ret.ImportAssets[key] = asset
ret.Analysis.ImportableAssetCount++
ret.Analysis.ImportableAssetSize += asset.Source.Size
}
ret.Analysis.UnreferencedFileCount = len(ret.ImportAssets) - len(ret.ReferencedAssets)
if ret.Analysis.UnreferencedFileCount < 0 {
ret.Analysis.UnreferencedFileCount = 0
}
progress(100, "Analysis completed")
return ret, nil
}
func validateObsidianVaultRoot(localPath string) (string, error) {
if strings.TrimSpace(localPath) == "" {View on GitHub (pinned to 9f775e8a12)