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

  1. Read the wrapped cause after 'failed:' — it names the exact field or validation that rejected the conf
  2. Fix the offending BoxConf field on the client side and retry the save
  3. Restore a known-good .siyuan/conf.json for the notebook if the on-disk file is corrupted or hand-edited
  4. 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

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)