siyuan-note/siyuan · error

box document ID [ ] does not match box ID [ ]

Error message

box document ID [%s] does not match box ID [%s]

What it means

The boxDocID stored in boxDoc.json must equal the notebook (box) ID, because the box doc node is the notebook's own root document. A mismatch means the metadata file belongs to a different notebook — likely copied, renamed, or stale — and readBoxDocID refuses to return an inconsistent identity.

Solutions

  1. Delete the stale .siyuan/boxDoc.json in the notebook so ensureBoxDoc0 rewrites it with the current box ID
  2. Edit boxDoc.json so boxDocID matches the notebook's directory ID (if intentional)
  3. When duplicating notebooks, use SiYuan's copy/import flow rather than copying raw data directories

Example fix

// before: copied from notebook 20240101120000-oldid01
{"spec": 1, "boxDocID": "20240101120000-oldid01"}
// after
{"spec": 1, "boxDocID": "20240101120000-newid01"}
Defensive patterns

Strategy: try-catch

Validate before calling

var probe struct{ BoxDocID string `json:"boxDocID"` }
if json.Unmarshal(data, &probe) == nil && probe.BoxDocID != boxID {
    // metadata from another notebook: delete and regenerate
}

Type guard

func matchesBox(data []byte, boxID string) bool {
    var m struct{ BoxDocID string `json:"boxDocID"` }
    return json.Unmarshal(data, &m) == nil && m.BoxDocID == boxID
}

Try / catch

if _, err := readBoxDocID(boxID); err != nil && strings.Contains(err.Error(), "does not match box ID") {
    // stale/copied metadata: remove .siyuan/boxDoc.json and let ensureBoxDoc0 rewrite it
}

Prevention

When it happens

Trigger: readBoxDocID (via ensureBoxDoc0 or TestBoxDocMetadataMatchesBoxID) finds meta.BoxDocID != boxID — e.g. the whole .siyuan directory was copied between notebooks, or the notebook folder was renamed without regenerating boxDoc.json.

Common situations: Duplicating a notebook by copying its data directory (boxDoc.json still names the old ID); renaming the notebook folder manually; sync restoring a boxDoc.json from another notebook.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/7f81d3821e33e53a. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/box_doc.go:80

	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)
}

func IsBoxDocEnabled() bool {
	return nil != Conf && nil != Conf.FileTree && nil != Conf.FileTree.BoxDocEnabled && *Conf.FileTree.BoxDocEnabled
}

func hiddenBoxDocRootIDs() (ret []string) {

View on GitHub (pinned to 9f775e8a12)