{"record":{"id":"7e21425564275e8f","repo":"JuliusBrussee/caveman","slug":"json-splice-invalid-element-insertion","errorCode":null,"errorMessage":"json splice: invalid element insertion","messagePattern":"json splice: invalid element insertion","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/providers/jsonsplice/jsonsplice.go","lineNumber":219,"sourceCode":"\t\treturn nil, fmt.Errorf(\"json splice: invalid array range\")\n\t}\n\tif len(elements) == 0 {\n\t\treturn body, nil\n\t}\n\n\tinsertAt := array.End - 1\n\tfor insertAt > array.Start+1 && bytes.ContainsRune([]byte(\" \\n\\r\\t\"), rune(body[insertAt-1])) {\n\t\tinsertAt--\n\t}\n\thasElements := insertAt > array.Start+1\n\n\tvar addition bytes.Buffer\n\tif hasElements {\n\t\taddition.WriteByte(',')\n\t}\n\tfor i, element := range elements {\n\t\tif !json.Valid(element) {\n\t\t\treturn nil, fmt.Errorf(\"json splice: invalid element insertion\")\n\t\t}\n\t\tif i > 0 {\n\t\t\taddition.WriteByte(',')\n\t\t}\n\t\taddition.Write(element)\n\t}\n\n\tout := make([]byte, 0, len(body)+addition.Len())\n\tout = append(out, body[:insertAt]...)\n\tout = append(out, addition.Bytes()...)\n\tout = append(out, body[insertAt:]...)\n\treturn out, nil\n}\n\nfunc value(body []byte, start int) (int, bool) {\n\ti := space(body, start)\n\tif i >= len(body) {\n\t\treturn 0, false","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/providers/jsonsplice/jsonsplice.go#L201-L237","documentation":"AppendArrayElements requires every element to be valid JSON because bytes are inserted verbatim before the closing bracket. Invalid element bytes abort the splice to prevent producing a corrupt document.","triggerScenarios":"Element built via string concatenation or fmt.Sprintf with unquoted strings; empty/nil element bytes; partially failed marshal passed through.","commonSituations":"Cache-point objects serialized with a non-JSON encoder; interpolating raw strings into []byte; a marshal error earlier ignored, leaving truncated JSON in the element.","solutions":["Build each element with json.Marshal and check its error before appending to the elements slice","Add json.Valid checks in tests for all element payloads","Never pass nil/empty bytes; skip the append entirely when there is nothing to insert"],"exampleFix":"// before: concatenated element\nelem := []byte(fmt.Sprintf(`{\"type\": %s}`, kind))\nout, err := jsonsplice.AppendArrayElements(body, span, elem)\n// after: marshal the struct\nraw, err := json.Marshal(cachePoint{Type: kind})\nif err != nil { return nil, err }\nout, err := jsonsplice.AppendArrayElements(body, span, raw)","handlingStrategy":"validation","validationCode":"for i, e := range elements {\n    if len(e) == 0 || !json.Valid(e) { return fmt.Errorf(\"element %d is not valid JSON: %q\", i, e) }\n}","typeGuard":null,"tryCatchPattern":"if err := validateElements(elements); err != nil { return nil, err }\nout, err := jsonsplice.AppendArrayElements(body, span, elements...)","preventionTips":["Marshal element structs with json.Marshal and check errors","Skip nil/empty elements instead of passing them through","Keep a json.Valid assertion in element-builder tests"],"tags":["json","go","byte-splice","validation"],"backgroundTag":"json-parse-error","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}