{"record":{"id":"2b0a41f17c49bdaa","repo":"JuliusBrussee/caveman","slug":"cacheengine-segment-exceeds-framing-limit","errorCode":null,"errorMessage":"cacheengine: segment exceeds framing limit","messagePattern":"cacheengine: segment exceeds framing limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cacheengine/engine.go","lineNumber":342,"sourceCode":"\tvar prefix []byte\n\tvar stable []Segment\n\tseenNames := map[string]bool{}\n\tfor _, segment := range segments {\n\t\tif !segment.Stable || !segment.Cacheable {\n\t\t\tbreak\n\t\t}\n\t\tif !validIdentity(segment.Name, 1024, false) || len(segment.Content) == 0 || seenNames[segment.Name] {\n\t\t\treturn nil, nil, errors.New(\"cacheengine: stable segment needs name and content\")\n\t\t}\n\t\tseenNames[segment.Name] = true\n\t\tif segment.Tokens < 0 || segment.ExpectedCalls < 0 {\n\t\t\treturn nil, nil, errors.New(\"cacheengine: negative segment measurement\")\n\t\t}\n\t\tif maxBytes < 8 || len(segment.Name) > maxBytes-8 || len(segment.Content) > maxBytes-8-len(segment.Name) || len(prefix) > maxBytes-8-len(segment.Name)-len(segment.Content) {\n\t\t\treturn nil, nil, errors.New(\"cacheengine: stable prefix exceeds configured byte limit\")\n\t\t}\n\t\tif len(segment.Name) > math.MaxUint32 || len(segment.Content) > math.MaxUint32 {\n\t\t\treturn nil, nil, errors.New(\"cacheengine: segment exceeds framing limit\")\n\t\t}\n\t\tprefix = appendFrame(prefix, segment.Name, segment.Content)\n\t\tstable = append(stable, segment)\n\t}\n\treturn prefix, stable, nil\n}\n\nfunc appendFrame(dst []byte, name string, content []byte) []byte {\n\tvar lengths [8]byte\n\tbinary.BigEndian.PutUint32(lengths[:4], uint32(len(name)))\n\tbinary.BigEndian.PutUint32(lengths[4:], uint32(len(content)))\n\tdst = append(dst, lengths[:]...)\n\tdst = append(dst, name...)\n\treturn append(dst, content...)\n}\n\nfunc breakpointCandidates(segments []Segment, defaultCalls int, profile Profile) ([]Breakpoint, bool, bool, error) {\n\tvar candidates []Breakpoint","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/cacheengine/engine.go#L324-L360","documentation":"Thrown by stablePrefix when len(segment.Name) or len(segment.Content) exceeds math.MaxUint32, because the 8-byte frame header encodes each length as a big-endian uint32. On 64-bit platforms this is practically unreachable (it requires a > 4 GiB name or content in a single segment) and is a defensive guard.","triggerScenarios":"A single stable segment whose Name or Content byte slice is larger than 4294967295 bytes; only possible when streaming/accumulating gigantic buffers into one segment.","commonSituations":"Essentially never in practice; would indicate a bug where the wrong slice (e.g. an entire file corpus or an unbounded reader's output) is attached as one segment's Content.","solutions":["Split oversized content into multiple stable segments below the byte limit (the maxBytes check at engine.go:339 will usually fire first anyway)","Check where the segment content is built: an unbounded io.ReadAll is almost certainly the real bug","Add an upper bound when accumulating segment content from readers"],"exampleFix":"// before\ncontent, _ := io.ReadAll(resp.Body) // unbounded\nseg := cacheengine.Segment{Name: \"corpus\", Stable: true, Cacheable: true, Content: content}\n\n// after\ncontent, _ := io.ReadAll(io.LimitReader(resp.Body, maxSegmentBytes))\nseg := cacheengine.Segment{Name: \"corpus\", Stable: true, Cacheable: true, Content: content}","handlingStrategy":"validation","validationCode":"for _, s := range segs { if uint64(len(s.Name)) > math.MaxUint32 || uint64(len(s.Content)) > math.MaxUint32 { return errors.New(\"segment too large\") } }","typeGuard":"// n/a","tryCatchPattern":null,"preventionTips":["Bound readers with io.LimitReader when building segment content","Split giant content into multiple segments"],"tags":["cacheengine","limits","framing","defensive","go"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}