siyuan-note/siyuan · error
panic during siyuan.storage.put
Error message
panic during siyuan.storage.put: %v
What it means
The goroutine performing the mkdir/write for siyuan.storage.put(path, content) recovered from a Go panic; the panic value is embedded and the Promise rejected. Normal I/O failures are reported with their own messages; this wrapper indicates an unexpected internal defect during the put pipeline.
Solutions
- Inspect the embedded panic value in the rejection for the concrete cause
- Serialize your plugin's storage.put calls (await each before the next) to rule out races
- Retry the put once — transient races often succeed on the second attempt
- Report reproducible panics with the message text to the SiYuan kernel maintainers
Example fix
// before
await Promise.all(paths.map(p => siyuan.storage.put(p, data)));
// after
for (const p of paths) {
try { await siyuan.storage.put(p, data); }
catch (e) { console.error("put failed:", e.message); }
} Defensive patterns
Strategy: try-catch
Validate before calling
if (typeof path !== "string" || typeof content !== "string") throw new TypeError("put requires string path and content"); Type guard
null
Try / catch
try { await siyuan.storage.put(path, content); } catch (e) { console.error("storage.put panic:", e.message); await retryOnce(() => siyuan.storage.put(path, content)); } Prevention
- Await each put before starting the next; avoid parallel writes to the same path
- Retry once on failure — many panic triggers are transient races
- Keep unusual characters and very long paths out of storage paths
- Report reproducible panics with the embedded value to SiYuan maintainers
When it happens
Trigger: A panic in os.MkdirAll, filelock.WriteFile, or the result/resolution code path inside the put goroutine; nil dereferences or slice bugs in the storage layer under concurrency or unusual filesystem states.
Common situations: Race conditions between concurrent puts from the same plugin; kernel-internal bugs; exotic filesystem states (e.g. path component becoming a file mid-write) that trip an unchecked assumption.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- panic during siyuan.storage.get
- failed to make directory
- failed to remove storage path from watcher
- failed to write file
- path and content required
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/a5fddff4d7f93b0f.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/plugin/api_storage.go:260
if argErr != nil {
err = argErr
return
}
if util.ReadOnly {
err = fmt.Errorf("The current kernel is in read-only mode, storage.put is not allowed")
return
}
abs, resolveErr := resolvePath(path)
if resolveErr != nil {
err = resolveErr
return
}
go func() (result any, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic during siyuan.storage.put: %v", r)
}
p.worker.Run(func(rt *goja.Runtime) (_ any, _ error) {
if lo.IsNil(err) {
if resolveErr := resolve(result); resolveErr != nil {
logging.LogErrorf("[plugin:%s] siyuan.storage.put resolve: %v", p.Name, resolveErr)
}
} else {
if rejectErr := reject(rt.NewGoError(err)); rejectErr != nil {
logging.LogErrorf("[plugin:%s] siyuan.storage.put reject: %v", p.Name, rejectErr)
}
}
return
}, nil)
}()
if mkdirErr := os.MkdirAll(filepath.Dir(abs), 0755); mkdirErr != nil {
err = fmt.Errorf("failed to make directory: %w", mkdirErr)View on GitHub (pinned to 9f775e8a12)