{"record":{"id":"825982439f37cceb","repo":"siyuan-note/siyuan","slug":"invalid-document-spec-s","errorCode":null,"errorMessage":"invalid document spec [%s]","messagePattern":"invalid document spec \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/treenode/tree.go","lineNumber":172,"sourceCode":"\t}\n\tif err := json.Unmarshal(data, &root); nil != err {\n\t\treturn err\n\t}\n\treturn CheckSpec(&parse.Tree{Root: &ast.Node{Spec: root.Spec}})\n}\n\nfunc CheckSpec(tree *parse.Tree) (err error) {\n\tif CurrentSpec == tree.Root.Spec || \"\" == tree.Root.Spec {\n\t\treturn\n\t}\n\n\tspec, err := strconv.Atoi(tree.Root.Spec)\n\tif nil != err {\n\t\tlogging.LogErrorf(\"parse spec [%s] failed: %s\", tree.Root.Spec, err)\n\t\treturn\n\t}\n\tif 1 > spec {\n\t\treturn fmt.Errorf(\"invalid document spec [%s]\", tree.Root.Spec)\n\t}\n\n\tcurrentSpec, _ := strconv.Atoi(CurrentSpec)\n\tif spec > currentSpec {\n\t\tlogging.LogErrorf(\"tree spec [%s] is newer than current spec [%s]\", tree.Root.Spec, CurrentSpec)\n\t\treturn ErrSpecTooNew\n\t}\n\treturn\n}\n\nfunc UpgradeSpec(tree *parse.Tree) (upgraded bool) {\n\toldSpec := tree.Root.Spec\n\tupgradeSpec1(tree)\n\tupgradeSpec2(tree)\n\tif \"2\" == tree.Root.Spec {\n\t\tast.Walk(tree.Root, func(node *ast.Node, entering bool) ast.WalkStatus {\n\t\t\tif entering && (ast.NodeTabs == node.Type || ast.NodeTabItem == node.Type) {\n\t\t\t\ttree.Root.Spec = \"3\"","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/treenode/tree.go#L154-L190","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set the document root's Spec to a valid positive integer (e.g. \"2\" or \"3\", at most CurrentSpec)","Restore the document from backup/sync history if the file was corrupted","Remove or regenerate the invalid document rather than re-saving it through the kernel"],"exampleFix":"// corrupted .sy root\n{ \"ID\": \"20240101120000-abcdefgh\", \"Spec\": \"0\", ... }\n// after fix\n{ \"ID\": \"20240101120000-abcdefgh\", \"Spec\": \"3\", ... }","handlingStrategy":"validation","validationCode":"spec, err := strconv.Atoi(tree.Root.Spec)\nif err != nil || spec < 1 {\n  return fmt.Errorf(\"invalid document spec %q\", tree.Root.Spec)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hand-edit the Spec field of .sy files","Validate generated documents set a Spec between BaseSpec (2) and CurrentSpec (3)","Restore corrupted documents from sync history or backups"],"tags":["document-spec","validation","corruption"],"backgroundTag":"invalid-config-value","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}