siyuan-note/siyuan · error
marshal box conf [ ] failed
Error message
marshal box conf [%s] failed: %w
What it means
SaveConf persists a notebook (box) configuration to <DataDir>/<boxID>/.siyuan/conf.json. Before writing it sanitizes the conf via prepareBoxConfForSave, then serializes it with gulu.JSON.MarshalIndentJSON. This error is returned when JSON marshaling of the prepared configuration fails, which is nearly impossible for plain BoxConf structs but can occur if the structure holds unmarshalable values (e.g. invalid types injected through channels, maps, or func fields).
Solutions
- Inspect the BoxConf object passed to SaveConf for fields holding func, channel, or invalid values and reset them to defaults
- Recreate the BoxConf with conf.NewBoxConf() and copy only known-good scalar fields before calling SaveConf
- Log the wrapped inner error (%w) to identify which value failed to marshal
- Update siyuan-note/gulu to the latest version in case of an encoding bug
Example fix
// before conf.FuncField = myFunc // unmarshalable err := box.SaveConf(conf) // after conf.FuncField = nil // or remove unsupported field err := box.SaveConf(conf)
Defensive patterns
Strategy: validation
Validate before calling
// Go: ensure conf contains only marshalable fields before SaveConf
b, err := json.Marshal(conf)
if err != nil {
return fmt.Errorf("box conf not serializable: %w", err)
} Try / catch
if err := box.SaveConf(conf); err != nil {
log.Printf("save conf failed: %v", err) // wrapped marshal error
} Prevention
- Do not inject func/channel values into BoxConf
- Reset BoxConf to defaults when in doubt
- Keep gulu dependency up to date
When it happens
Trigger: Calling Box.SaveConf(conf) when gulu.JSON.MarshalIndentJSON(persisted) fails; in practice this happens only if the persisted BoxConf contains a value encoding/json cannot marshal (func, channel, or a custom Marshaler returning an error), e.g. after programmatic corruption of the conf object.
Common situations: Plugin or test code mutating a BoxConf struct with unsupported field values; memory pressure bugs; a defective custom marshaling hook; essentially never from normal UI use.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- marshal master password migration failed
- decode existing session data failed
- decode session data failed
- encode session data failed
- invalid pinned document
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/aff246df23331d05.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/box.go:342
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)
}
if err = box.saveConf0(newData); err != nil {
return err
}
return syncBoxConfCryptoBackup(box.ID, persisted)View on GitHub (pinned to 9f775e8a12)