siyuan-note/siyuan · error
prepare box conf [ ] failed
Error message
prepare box conf [%s] failed: %w
What it means
Box.SaveConf persists a notebook's .siyuan/conf.json. Before writing, prepareBoxConfForSave validates/normalizes the configuration; if that preparation fails, the error is wrapped as "prepare box conf [<path>] failed: <cause>". The inner cause carries the actual problem (e.g. an invalid field value or type in the BoxConf), while the outer message identifies which notebook's conf file was involved.
Solutions
- Read the wrapped cause after 'failed:' — it names the exact field or validation that rejected the conf
- Fix the offending BoxConf field on the client side and retry the save
- Restore a known-good .siyuan/conf.json for the notebook if the on-disk file is corrupted or hand-edited
- If triggered programmatically, validate the conf object before calling SaveConf
Example fix
// before: posting invalid conf
fetchPost("/api/notebook/saveConf notebook", {notebook: boxID, conf: {sortMode: "not-a-number"}})
// after
fetchPost("/api/notebook/saveConf notebook", {notebook: boxID, conf: {sortMode: 0}}) Defensive patterns
Strategy: try-catch
Validate before calling
function validateBoxConfBeforeSave(conf) {
// mirror prepareBoxConfForSave checks: required fields present, types correct
return conf != null && typeof conf === "object";
} Type guard
function isBoxConf(c) {
return typeof c === "object" && c !== null && !Array.isArray(c);
} Try / catch
err := box.SaveConf(conf)
if err != nil {
var wrapped = err.Error() // "prepare box conf [<path>] failed: <cause>"
// log wrapped cause and surface to caller; do not retry blindly
} Prevention
- Always inspect the wrapped cause after 'failed:' — it identifies the offending conf field
- Do not hand-edit .siyuan/conf.json; change settings through the API/UI
- Keep clients updated with the BoxConf schema
- Validate conf payloads before calling save endpoints
When it happens
Trigger: Any API path that saves notebook configuration while prepareBoxConfForSave returns an error — e.g. setting a box conf field to a value that fails validation (invalid type, out-of-range or forbidden value) via conf-saving endpoints or API contract tests exercising block/heading transactions that touch box conf.
Common situations: A client (plugin, script, third-party tool) posting a malformed box configuration to the kernel API; stale or hand-edited conf.json contents clashing with the validator; regression tests feeding unusual conf values.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/4189937a52e9b032.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/box.go:338
logging.LogErrorf("parse box conf [%s] failed: %s", confPath, err)
return
}
if ret.Encrypted {
if err = revealBoxMetadataIfUnlocked(box.ID, ret); err != nil {
logging.LogErrorf("decrypt encrypted notebook metadata [%s] failed: %s", box.ID, err)
}
} else {
ret.Icon = filterBoxIcon(ret.Icon)
}
return
}
func (box *Box) SaveConf(conf *conf.BoxConf) error {
confPath := filepath.Join(util.DataDir, box.ID, ".siyuan/conf.json")
persisted, err := prepareBoxConfForSave(box.ID, conf)
if err != nil {
return fmt.Errorf("prepare box conf [%s] failed: %w", confPath, err)
}
newData, err := gulu.JSON.MarshalIndentJSON(persisted, "", " ")
if err != nil {
return fmt.Errorf("marshal box conf [%s] failed: %w", confPath, err)
}
oldData, err := filelock.ReadFile(confPath)
if err != nil {
if err = box.saveConf0(newData); err != nil {
return err
}
return syncBoxConfCryptoBackup(box.ID, persisted)
}
if bytes.Equal(newData, oldData) {
return syncBoxConfCryptoBackup(box.ID, persisted)
}
View on GitHub (pinned to 9f775e8a12)