siyuan-note/siyuan · error

invalid box document ID

Error message

invalid box document ID [%s]

What it means

The boxDocID field inside boxDoc.json must be a valid SiYuan node ID (ast.IsNodeIDPattern: timestamp-suffix format). This error means the stored ID is malformed — empty string, wrong characters, or truncated — so the notebook's document-node identity cannot be trusted.

Solutions

  1. Fix boxDocID in .siyuan/boxDoc.json to the notebook's actual node ID (timestamp-randomid format)
  2. Simplest: delete .siyuan/boxDoc.json and let SiYuan regenerate it via writeBoxDocID with the correct box ID
  3. If the notebook's root document .sy file was renamed/re-IDed, align boxDoc.json with the new ID or recreate the notebook doc node

Example fix

// before
{"spec": 1, "boxDocID": "mynotebook"}
// after
{"spec": 1, "boxDocID": "20240101120000-abcdefg"}
Defensive patterns

Strategy: validation

Validate before calling

var probe struct{ BoxDocID string `json:"boxDocID"` }
if json.Unmarshal(data, &probe) == nil && !ast.IsNodeIDPattern(probe.BoxDocID) {
    // invalid ID: delete boxDoc.json so it is rewritten with the box ID
}

Type guard

func validBoxDocID(id string) bool { return ast.IsNodeIDPattern(id) }

Try / catch

if _, err := readBoxDocID(boxID); err != nil && strings.Contains(err.Error(), "invalid box document ID") {
    // regenerate boxDoc.json via writeBoxDocID
}

Prevention

When it happens

Trigger: readBoxDocID parses a boxDoc.json whose boxDocID fails ast.IsNodeIDPattern, e.g. {"spec":1,"boxDocID":""} or a hand-typed/nonstandard identifier.

Common situations: Manual editing of boxDoc.json with an invented ID; a tool writing the field as a non-ID string; an older/buggy writer producing an empty boxDocID.

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/158ad0520630287f. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/box_doc.go:77

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

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

View on GitHub (pinned to 9f775e8a12)