{"record":{"id":"2b1c20592a5c3a31","repo":"hyperledger/fabric","slug":"object-already-open-must-close-object-before-star","errorCode":null,"errorMessage":"object already open, must close object before starting a new one","messagePattern":"object already open, must close object before starting a new one","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ledgerutil/jsonrw/json_read_write.go","lineNumber":78,"sourceCode":"func NewJSONFileWriter(filePath string) (*JSONFileWriter, error) {\n\tf, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0o644)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb := bufio.NewWriter(f)\n\n\treturn &JSONFileWriter{\n\t\tfile:    f,\n\t\tbuffer:  b,\n\t\tencoder: json.NewEncoder(b),\n\t}, nil\n}\n\n// Open a json object\nfunc (w *JSONFileWriter) OpenObject() error {\n\tif w.objectOpened {\n\t\treturn errors.Errorf(\"object already open, must close object before starting a new one\")\n\t}\n\n\tw.objectOpened = true\n\t_, err := w.buffer.Write([]byte(\"{\\n\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Close a json object\nfunc (w *JSONFileWriter) CloseObject() error {\n\tif !w.objectOpened {\n\t\treturn errors.Errorf(\"no object open, cannot close object\")\n\t}\n\n\t_, err := w.buffer.Write([]byte(\"}\\n\"))","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/internal/ledgerutil/jsonrw/json_read_write.go#L60-L96","documentation":"JSONFileWriter serializes one top-level JSON object field at a time, tracking nesting with an objectOpened flag. OpenObject throws if an object is already open, because JSON cannot nest a bare '{' without a field and the writer enforces open/close discipline.","triggerScenarios":"Calling OpenObject twice without an intervening CloseObject on the same JSONFileWriter.","commonSituations":"Loop refactoring bugs where OpenObject is inside a loop instead of outside it, or a forgotten CloseObject on an early-return path.","solutions":["Call CloseObject before each new OpenObject","Move OpenObject out of loops that iterate multiple times","Check error returns of CloseObject so an early return does not leave the object open","Restructure code to open/close per item inside the loop rather than around it"],"exampleFix":"// before\nw.OpenObject()\nfor _, v := range items { w.OpenObject() }\n// after\nfor _, v := range items {\n    w.OpenObject()\n    w.AddField(\"key\", v)\n    w.CloseObject()\n}","handlingStrategy":"validation","validationCode":"type openTracker struct{ objOpen, listOpen bool }","typeGuard":"func canOpenObject(w *jsonrw.JSONFileWriter, tracked bool) bool { return !tracked }","tryCatchPattern":"if err := w.OpenObject(); err != nil {\n\treturn fmt.Errorf(\"open object: %w\", err)\n}\ndefer func() {\n\tif err := w.CloseObject(); err != nil { log.Error(err) }\n}()","preventionTips":["Pair every OpenObject with a CloseObject immediately via defer","Never place OpenObject inside loops","Check OpenObject/CloseObject return values instead of ignoring errors","Track open state in a local variable when writing complex nested output"],"tags":["hyperledger-fabric","json","state-machine","api-misuse"],"backgroundTag":"json-writer-object-already-open","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}