siyuan-note/siyuan · error

invalid document spec [%s]

Error message

invalid document spec [%s]

What it means

CheckSpec validates a tree's root Spec: it must parse as an integer >= 1, otherwise this error is returned. Values above the current supported spec produce the distinct ErrSpecTooNew instead. This guards against corrupt or malformed spec fields before the tree is used for reads or writes.

Source

Thrown at kernel/treenode/tree.go:172

	}
	if err := json.Unmarshal(data, &root); nil != err {
		return err
	}
	return CheckSpec(&parse.Tree{Root: &ast.Node{Spec: root.Spec}})
}

func CheckSpec(tree *parse.Tree) (err error) {
	if CurrentSpec == tree.Root.Spec || "" == tree.Root.Spec {
		return
	}

	spec, err := strconv.Atoi(tree.Root.Spec)
	if nil != err {
		logging.LogErrorf("parse spec [%s] failed: %s", tree.Root.Spec, err)
		return
	}
	if 1 > spec {
		return fmt.Errorf("invalid document spec [%s]", tree.Root.Spec)
	}

	currentSpec, _ := strconv.Atoi(CurrentSpec)
	if spec > currentSpec {
		logging.LogErrorf("tree spec [%s] is newer than current spec [%s]", tree.Root.Spec, CurrentSpec)
		return ErrSpecTooNew
	}
	return
}

func UpgradeSpec(tree *parse.Tree) (upgraded bool) {
	oldSpec := tree.Root.Spec
	upgradeSpec1(tree)
	upgradeSpec2(tree)
	if "2" == tree.Root.Spec {
		ast.Walk(tree.Root, func(node *ast.Node, entering bool) ast.WalkStatus {
			if entering && (ast.NodeTabs == node.Type || ast.NodeTabItem == node.Type) {
				tree.Root.Spec = "3"

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Set the document root's Spec to a valid positive integer (e.g. "2" or "3", at most CurrentSpec)
  2. Restore the document from backup/sync history if the file was corrupted
  3. Remove or regenerate the invalid document rather than re-saving it through the kernel

Example fix

// corrupted .sy root
{ "ID": "20240101120000-abcdefgh", "Spec": "0", ... }
// after fix
{ "ID": "20240101120000-abcdefgh", "Spec": "3", ... }
Defensive patterns

Strategy: validation

Validate before calling

spec, err := strconv.Atoi(tree.Root.Spec)
if err != nil || spec < 1 {
  return fmt.Errorf("invalid document spec %q", tree.Root.Spec)
}

Prevention

When it happens

Trigger: Loading or normalizing a .sy document whose Root.Spec is not a valid positive integer — e.g. Spec is empty, "0", negative, or non-numeric text; called from NormalizeTreeForRead, prepareWriteTree, fixTreeJSONData, parseJSON2Tree, and CheckSpecJSON.

Common situations: Hand-edited or partially corrupted .sy files; third-party tools generating documents with a missing or zero Spec field; merge conflicts truncating the JSON root.

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@8641553a1f (2026-09-11). Data as JSON: /api/errors/825982439f37cceb. Report an issue: GitHub.