{"record":{"id":"5fa88404a4b7d75e","repo":"siyuan-note/siyuan","slug":"marshal-box-document-metadata-failed-w","errorCode":null,"errorMessage":"marshal box document metadata failed: %w","messagePattern":"marshal box document metadata failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/box_doc.go","lineNumber":89,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"unmarshal box document metadata failed: %w\", err)\n\t}\n\tif boxDocMetaSpec != meta.Spec {\n\t\treturn \"\", fmt.Errorf(\"unsupported box document metadata spec [%d]\", meta.Spec)\n\t}\n\tif !ast.IsNodeIDPattern(meta.BoxDocID) {\n\t\treturn \"\", fmt.Errorf(\"invalid box document ID [%s]\", meta.BoxDocID)\n\t}\n\tif boxID != meta.BoxDocID {\n\t\treturn \"\", fmt.Errorf(\"box document ID [%s] does not match box ID [%s]\", meta.BoxDocID, boxID)\n\t}\n\treturn boxID, nil\n}\n\nfunc writeBoxDocID(boxID string) error {\n\tmeta := &boxDocMeta{Spec: boxDocMetaSpec, BoxDocID: boxID}\n\tdata, err := gulu.JSON.MarshalIndentJSON(meta, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal box document metadata failed: %w\", err)\n\t}\n\treturn filelock.WriteFile(boxDocMetaPath(boxID), data)\n}\n\nfunc IsBoxDocEnabled() bool {\n\treturn nil != Conf && nil != Conf.FileTree && nil != Conf.FileTree.BoxDocEnabled && *Conf.FileTree.BoxDocEnabled\n}\n\nfunc hiddenBoxDocRootIDs() (ret []string) {\n\tif IsBoxDocEnabled() || nil == Conf {\n\t\treturn\n\t}\n\tfor _, box := range Conf.GetOpenedBoxes() {\n\t\tret = append(ret, box.ID)\n\t}\n\treturn\n}\n","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/box_doc.go#L71-L107","documentation":"This error is returned by writeBoxDocID when gulu.JSON.MarshalIndentJSON fails to serialize the boxDocMeta struct into indented JSON. Since the struct contains only an int and a string, marshaling practically never fails — it would require a unsupported value reaching the encoder — so this error is an internal-invariant safeguard; the error is wrapped with %w and propagates from ensureBoxDoc0 and the import path.","triggerScenarios":"writeBoxDocID(boxID) is called by ensureBoxDoc0 (when the stored box document ID differs from the box ID, e.g. after enabling the box-doc feature or creating the box document) or during importSY0 / TestImportNotebookSYAsChildDocuments, and the JSON encoder fails on the meta struct.","commonSituations":"Essentially only reproducible by modifying the boxDocMeta struct to include a field the JSON encoder cannot handle (e.g. a chan, func, or cyclic value), or by an encoding defect in a custom gulu build; users should not encounter it in normal operation.","solutions":["Inspect the wrapped error's message from the log to identify which value the encoder rejected","Review recent changes to the boxDocMeta struct or gulu JSON code; revert any field that is not JSON-encodable","Update to a current SiYuan build in case a dependency defect in gulu was fixed","If seen in production with stock code, capture the full stack trace and report it upstream, since stock boxDocMeta should always marshal"],"exampleFix":"// before: non-encodable field breaks marshal\ntype boxDocMeta struct {\n    Spec     int    `json:\"spec\"`\n    BoxDocID string `json:\"boxDocID\"`\n    Hooks    func() `json:\"hooks\"` // unsupported by encoder\n}\n// after: keep only JSON-encodable fields\ntype boxDocMeta struct {\n    Spec     int    `json:\"spec\"`\n    BoxDocID string `json:\"boxDocID\"`\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"if err := writeBoxDocID(boxID); err != nil {\n    if strings.Contains(err.Error(), \"marshal box document metadata failed\") {\n        // serialization bug: log full wrapped error and skip sync of this change\n        logging.LogErrorf(\"box doc metadata marshal failed for box %s: %s\", boxID, err)\n        return err\n    }\n    return err\n}","preventionTips":["Keep the boxDocMeta struct limited to JSON-encodable primitives (int, string)","Do not replace gulu's JSON package with custom builds without running the metadata tests","Run TestBoxDocMetadataMatchesBoxID after any change touching box document metadata","Treat any occurrence in production with stock code as a bug report, not a user-fixable condition"],"tags":["json","serialization","notebook-metadata","internal"],"backgroundTag":"json-marshal-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}