{"record":{"id":"0d8deb3fc9dbfb2f","repo":"siyuan-note/siyuan","slug":"failed-to-write-file-w","errorCode":null,"errorMessage":"failed to write file: %w","messagePattern":"failed to write file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_storage.go","lineNumber":282,"sourceCode":"\t\t\t\t\t\tif lo.IsNil(err) {\n\t\t\t\t\t\t\tif resolveErr := resolve(result); resolveErr != nil {\n\t\t\t\t\t\t\t\tlogging.LogErrorf(\"[plugin:%s] siyuan.storage.put resolve: %v\", p.Name, resolveErr)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {\n\t\t\t\t\t\t\t\tlogging.LogErrorf(\"[plugin:%s] siyuan.storage.put reject: %v\", p.Name, rejectErr)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n\t\t\t\t\t}, nil)\n\t\t\t\t}()\n\n\t\t\t\tif mkdirErr := os.MkdirAll(filepath.Dir(abs), 0755); mkdirErr != nil {\n\t\t\t\t\terr = fmt.Errorf(\"failed to make directory: %w\", mkdirErr)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif writeErr := filelock.WriteFile(abs, []byte(content)); writeErr != nil {\n\t\t\t\t\terr = fmt.Errorf(\"failed to write file: %w\", writeErr)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}()\n\n\t\t\treturn\n\t\t}, func(rt *goja.Runtime, result any, err error) {\n\t\t\tif !lo.IsNil(err) {\n\t\t\t\tif rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {\n\t\t\t\t\tlogging.LogErrorf(\"[plugin:%s] siyuan.storage.put reject: %v\", p.Name, rejectErr)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tif runErr != nil {\n\t\t\tlogging.LogErrorf(\"[plugin:%s] siyuan.storage.put worker run: %v\", p.Name, runErr)\n\t\t\tif rejectErr := reject(rt.NewGoError(runErr)); rejectErr != nil {\n\t\t\t\tlogging.LogErrorf(\"[plugin:%s] siyuan.storage.put reject: %v\", p.Name, rejectErr)\n\t\t\t}","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/plugin/api_storage.go#L264-L300","documentation":"Thrown when filelock.WriteFile fails to write the bytes to the target file. filelock is SiYuan's cross-platform locked file writer; it returns an error on permission denial, disk full, read-only filesystem, the target being a directory, or a lock acquisition failure. The error is wrapped with %w so the underlying cause is preserved.","triggerScenarios":"put('state.json', body) where 'state.json' is actually a directory; disk full; permission denied; the file is held with an incompatible lock by another process; storage volume mounted read-only.","commonSituations":"Plugin overwrote a path that a prior step created as a directory; shared workspace accessed by two kernel instances racing on the same file; disk quota exhausted on the storage volume.","solutions":["Unwrap the error to read the OS-level cause (ENOENT, EACCES, ENOSPC, EISDIR).","Confirm the target path is not a directory; if so, choose a different path or remove the directory.","Free disk space or raise the storage quota.","Ensure only one kernel process owns the workspace to avoid lock contention."],"exampleFix":"// before\nawait siyuan.storage.put(path, body); // path is a directory\n// after\n// pick a file path that is not an existing directory:\nawait siyuan.storage.put(path + '.json', body);","handlingStrategy":"try-catch","validationCode":"// Pre-flight: ensure target is not an existing directory before writing.","typeGuard":null,"tryCatchPattern":"try {\n  await siyuan.storage.put(path, body);\n} catch (e) {\n  if (/failed to write file/.test(String(e))) {\n    const cause = String(e);\n    if (/EISDIR|is a directory/.test(cause)) { /* pick a different path */ }\n    else if (/ENOSPC/.test(cause)) { /* free disk space */ }\n    else throw e;\n  } else throw e;\n}","preventionTips":["Do not reuse a directory path as a file path.","Ensure only one kernel process owns the workspace to avoid filelock contention.","Monitor free disk space on the storage volume."],"tags":["plugin-api","storage","filesystem","io-error","filelock","permissions"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}