{"record":{"id":"8ac0d980571ab3bc","repo":"siyuan-note/siyuan","slug":"path-size-or-modification-time-differs","errorCode":null,"errorMessage":"path, size or modification time differs","messagePattern":"path, size or modification time differs","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/import_obsidian.go","lineNumber":1866,"sourceCode":"\tfor _, asset := range vault.ImportAssets {\n\t\tif err := ctx.Err(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := validateObsidianSourceMetadata(asset.Source); err != nil {\n\t\t\treturn newObsidianUserError(346, asset.Source.RelPath,\n\t\t\t\tfmt.Errorf(\"attachment [%s] changed after analysis: %w\", asset.Source.RelPath, err))\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validateObsidianSourceMetadata(file *obsidianSourceFile) error {\n\tinfo, err := os.Stat(file.AbsPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif info.Size() != file.Size || !info.ModTime().Equal(file.ModTime) {\n\t\treturn errors.New(\"path, size or modification time differs\")\n\t}\n\treturn nil\n}\n\nfunc transformObsidianMarkdown(vault *obsidianVaultContext, doc *obsidianDocPlan, data []byte) ([]byte, *obsidianTransformStats) {\n\tscan := scanObsidianSource(data)\n\tstats := &obsidianTransformStats{ReservedIDs: map[string]bool{}, FootnoteIDs: map[string]bool{}, PreservedComments: len(scan.Comments)}\n\tfor _, heading := range doc.Headings {\n\t\tstats.ReservedIDs[heading.ID] = true\n\t}\n\tfor _, id := range doc.BlockIDs {\n\t\tstats.ReservedIDs[id] = true\n\t}\n\n\ttype replacement struct {\n\t\tstart int\n\t\tend   int\n\t\ttext  string","sourceCodeStart":1848,"sourceCodeEnd":1884,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/import_obsidian.go#L1848-L1884","documentation":"validateObsidianSourceMetadata stats the source file on disk and compares its size and modification time with the metadata recorded during the vault analysis phase. Any difference means the file changed after analysis, so the import treats it as untrustworthy and fails; it is the sentinel message wrapped by error 346.","triggerScenarios":"os.Stat succeeds on file.AbsPath but info.Size() != file.Size or info.ModTime() is not exactly equal to the file.ModTime recorded at analysis time.","commonSituations":"Attachment saved/rewritten after import started; tools that rewrite a file (formatters, editors, sync clients) even if content is identical but size/mtime changed; filesystems with coarse or shifting timestamp precision; files replaced by a newer version during the import window.","solutions":["Ensure no process writes to the Obsidian vault between starting the import and its completion","Re-run the import; the fresh analysis will record current size/mtime and validation will pass","Import from a read-only or frozen copy of the vault","Check for sync/backup tools resetting mtimes on vault files"],"exampleFix":"// before: file modified after analysis -> info.Size() != file.Size\nif info.Size() != file.Size || !info.ModTime().Equal(file.ModTime) {\n\treturn errors.New(\"path, size or modification time differs\")\n}\n// after (caller-side): re-run analysis so recorded metadata matches disk\nvault := analyzeVault(vaultPath) // fresh Stat metadata\nerr := importVault(vault) // validation now passes","handlingStrategy":"validation","validationCode":"info, err := os.Stat(absPath)\nif err != nil { return err }\nif info.Size() != recorded.Size || !info.ModTime().Equal(recorded.ModTime) {\n\treturn fmt.Errorf(\"%s changed since analysis\", recorded.RelPath)\n}","typeGuard":null,"tryCatchPattern":"if err := importObsidianVault(p, nb); err != nil && strings.Contains(err.Error(), \"modification time differs\") {\n\tvault = analyzeVault(p); err = importVault(vault) // re-analyze and retry\n}","preventionTips":["Re-run analysis immediately before import so Stat metadata is fresh","Avoid tools that rewrite or touch vault files during import","Import from a read-only copy of the vault"],"tags":["obsidian","import","file-stat","mtime"],"backgroundTag":"checksum-mismatch","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}