siyuan-note/siyuan · error
unsupported box document metadata spec [%d]
Error message
unsupported box document metadata spec [%d]
What it means
This error is returned by readBoxDocID when boxDoc.json parses but its `spec` field does not equal the version this kernel build supports (boxDocMetaSpec = 1). The spec field guards the box-document metadata format: if a future or past SiYuan version wrote a different schema, this build refuses to interpret it instead of misreading unknown fields. It is a forward/backward compatibility check on the metadata format version.
Source
Thrown at kernel/model/box_doc.go:74
}
return "/" + boxID + ".sy"
}
func readBoxDocID(boxID string) (ret string, err error) {
data, err := filelock.ReadFile(boxDocMetaPath(boxID))
if err != nil {
if errors.Is(err, os.ErrNotExist) {
err = nil
}
return
}
meta := &boxDocMeta{}
if err = gulu.JSON.UnmarshalJSON(data, meta); err != nil {
return "", fmt.Errorf("unmarshal box document metadata failed: %w", err)
}
if boxDocMetaSpec != meta.Spec {
return "", fmt.Errorf("unsupported box document metadata spec [%d]", meta.Spec)
}
if !ast.IsNodeIDPattern(meta.BoxDocID) {
return "", fmt.Errorf("invalid box document ID [%s]", meta.BoxDocID)
}
if boxID != meta.BoxDocID {
return "", fmt.Errorf("box document ID [%s] does not match box ID [%s]", meta.BoxDocID, boxID)
}
return boxID, nil
}
func writeBoxDocID(boxID string) error {
meta := &boxDocMeta{Spec: boxDocMetaSpec, BoxDocID: boxID}
data, err := gulu.JSON.MarshalIndentJSON(meta, "", " ")
if err != nil {
return fmt.Errorf("marshal box document metadata failed: %w", err)
}
return filelock.WriteFile(boxDocMetaPath(boxID), data)
}View on GitHub (pinned to 8641553a1f)
Solutions
- Use the SiYuan version that matches the spec written in boxDoc.json (upgrade the kernel if the file is newer)
- Check the file's spec value; if the file was hand-edited or the spec type changed, set it to the numeric literal 1
- If you intentionally want the feature re-initialized, back up the notebook, delete .siyuan/boxDoc.json, and let ensureBoxDoc0 recreate it with the current spec
- Do not edit spec by hand to silence the error unless you understand the schema — a mismatched schema will surface as other errors
Example fix
// before: missing/string spec field
{"boxDocID": "20240101120000-abcdefg"}
{"spec": "1", "boxDocID": "20240101120000-abcdefg"}
// after: numeric spec matching boxDocMetaSpec (= 1)
{"spec": 1, "boxDocID": "20240101120000-abcdefg"} Defensive patterns
Strategy: validation
Validate before calling
// Go: pre-check the spec field before invoking kernel APIs that touch box metadata
raw, _ := os.ReadFile(filepath.Join(util.DataDir, boxID, ".siyuan", "boxDoc.json"))
var m struct {
Spec int `json:"spec"`
}
if json.Unmarshal(raw, &m) == nil && m.Spec != 1 {
// unsupported spec: upgrade/downgrade SiYuan or remove the file to regenerate
fmt.Printf("boxDoc.json spec=%d, this build supports spec=1\n", m.Spec)
} Type guard
func specSupported(raw []byte) bool {
var m struct {
Spec *int `json:"spec"`
}
if json.Unmarshal(raw, &m) != nil || m.Spec == nil {
return false
}
return *m.Spec == 1
} Try / catch
if _, err := EnsureBoxDoc(boxID); err != nil {
if strings.Contains(err.Error(), "unsupported box document metadata spec") {
// migrate: back up, remove stale metadata, let the kernel recreate it
os.Rename(filepath.Join(util.DataDir, boxID, ".siyuan", "boxDoc.json"),
filepath.Join(util.DataDir, boxID, ".siyuan", "boxDoc.json.bak"))
_, err = EnsureBoxDoc(boxID)
}
} Prevention
- Run one SiYuan version consistently; avoid rolling the kernel back over data written by newer versions
- Pin spec to the numeric literal 1 if you ever construct the file programmatically
- After version upgrades, watch sync logs for metadata-format warnings across devices
- Do not share one workspace directory between different SiYuan versions simultaneously
When it happens
Trigger: readBoxDocID(boxID) reads a boxDoc.json whose numeric `spec` value is anything other than 1 — e.g. the file was produced by a newer SiYuan build that bumped the spec, or was hand-written with spec 0, "1" (string instead of number decodes as 0), or a missing spec field (decodes as 0).
Common situations: Rolling back the kernel to an older version after a newer version upgraded the metadata spec; mixing workspace data between different SiYuan versions via sync; hand-crafting the metadata file without knowing the required spec value; a JSON schema edit that changed spec's type so it unmarshals as 0.
Related errors
- invalid boot appearance selection
- Please initialize the data repo key first in [Settings - Acc
- invalid agent permission mode
- provider base URL is required
- invalid provider config
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/891ecc532615952b.
Report an issue: GitHub.