{"record":{"id":"aa5a8c8dc82b9c88","repo":"juicedata/juicefs","slug":"segment-s-is-nil","errorCode":null,"errorMessage":"segment %s is nil","messagePattern":"segment (.+?) is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/backup.go","lineNumber":327,"sourceCode":"\t\t\treturn uint64(len(b.Xattrs))\n\t\tcase segTypeAcl:\n\t\t\treturn uint64(len(b.Acls))\n\t\tcase segTypeStat:\n\t\t\treturn uint64(len(b.Dirstats))\n\t\tcase segTypeQuota:\n\t\t\treturn uint64(len(b.Quotas) + len(b.UserQuotas) + len(b.GroupQuotas))\n\t\tcase segTypeParent:\n\t\t\treturn uint64(len(b.Parents))\n\t\tcase segTypeChangeLog:\n\t\t\treturn uint64(len(b.Changelogs))\n\t\t}\n\t\treturn 0\n\t}\n}\n\nfunc (s *BakSegment) Marshal(w io.Writer) (int, error) {\n\tif s == nil || s.val == nil {\n\t\treturn 0, fmt.Errorf(\"segment %s is nil\", s)\n\t}\n\n\tif err := binary.Write(w, binary.BigEndian, s.typ); err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to write segment type %s : %w\", s, err)\n\t}\n\tdata, err := proto.Marshal(s.val)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to marshal segment message %s : %w\", s, err)\n\t}\n\ts.len = uint64(len(data))\n\tif err := binary.Write(w, binary.BigEndian, s.len); err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to write segment length %s: %w\", s, err)\n\t}\n\n\tif n, err := w.Write(data); err != nil || n != len(data) {\n\t\treturn 0, fmt.Errorf(\"failed to write segment data %s: err %w, write len %d, expect len %d\", s, err, n, len(data))\n\t}\n","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/backup.go#L309-L345","documentation":"BakSegment.Marshal refuses to serialize a segment when either the BakSegment pointer is nil or its val (the embedded proto.Message) is nil. This is an internal invariant check during backup writing: writeFooter/the segment writer should never hand Marshal a segment without a payload.","triggerScenarios":"Passing nil to Marshal directly; constructing a segment whose proto.Message was never set; a caller that built a BakSegment but skipped newBakSegment initialization; code paths that append a segment before populating val.","commonSituations":"Custom tooling built on the internal BakFormat API writing backup files; a bug where a nil batch was appended after filtering produced no content; reusing a BakSegment value after it was reset; reflection-based code creating a BakSegment without initializing fields.","solutions":["Initialize segments via newBakSegment(val) with a non-nil proto.Message instead of constructing BakSegment literals.","Check the segment slice before writing: skip or error on nil segments rather than attempting to marshal them.","If newBakSegment returned nil (a pb.Batch with no recognized field set), do not append it — that nil return means 'nothing to write'.","Ensure val is populated before Marshal is invoked (assign the *pb.Format or *pb.Batch before queuing the segment)."],"exampleFix":"// before: appending possibly-nil segment\nseg := newBakSegment(batch)\nsegments = append(segments, seg)\n\n// after: skip nil segments\nseg := newBakSegment(batch)\nif seg == nil {\n    return nil // empty batch: nothing to serialize\n}\nsegments = append(segments, seg)","handlingStrategy":"validation","validationCode":"if seg == nil || seg.val == nil {\n    return errors.New(\"refusing to marshal nil segment\")\n}","typeGuard":"func validSegment(s *BakSegment) bool { return s != nil && s.val != nil }","tryCatchPattern":"n, err := seg.Marshal(w)\nif err != nil {\n    if strings.Contains(err.Error(), \"is nil\") {\n        return fmt.Errorf(\"programming bug: nil segment queued for backup: %w\", err)\n    }\n    return err\n}","preventionTips":["Always construct segments through newBakSegment, never as raw literals.","Treat newBakSegment's nil return (empty batch) as 'skip', never append it.","Filter nil entries from the segment list before the write loop.","Assign val before enqueueing a segment for writing."],"tags":["protobuf","backup","nil-value","invariant"],"backgroundTag":"null-argument","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}