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

  1. Open the reported attachment path in Obsidian/file manager to confirm it exists and is readable, then re-run the import
  2. Fix OS-level causes: download cloud-placeholder files, grant read permission, shorten the path
  3. Remove or repair the broken link in the note if the attachment is truly gone, then re-import
  4. 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

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)