{"record":{"id":"d706ff080fd956c3","repo":"JuliusBrussee/caveman","slug":"helicone-decode-w","errorCode":null,"errorMessage":"helicone decode: %w","messagePattern":"helicone decode: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/importers/helicone.go","lineNumber":67,"sourceCode":"\trecs, err := decodeHelicone(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\trows := make([]Span, 0, len(recs))\n\tfor _, rec := range recs {\n\t\trows = append(rows, mapHelicone(rec, opts))\n\t}\n\treturn rows, nil\n}\n\nfunc decodeHelicone(data []byte) ([]heliconeRecord, error) {\n\tvar env heliconeEnvelope\n\tif err := json.Unmarshal(data, &env); err == nil && env.Data != nil {\n\t\treturn env.Data, nil\n\t}\n\tvar arr []heliconeRecord\n\tif err := json.Unmarshal(data, &arr); err != nil {\n\t\treturn nil, fmt.Errorf(\"helicone decode: %w\", err)\n\t}\n\treturn arr, nil\n}\n\nfunc mapHelicone(rec heliconeRecord, opts Options) Span {\n\tts, _ := parseTimeFlexible(rec.CreatedAt)\n\n\tmodel := rec.Response.Model\n\tif model == \"\" {\n\t\tmodel = rec.Request.Model\n\t}\n\tprovider := rec.Provider\n\tif provider == \"\" {\n\t\tprovider = rec.Request.Provider\n\t}\n\n\t// 2xx is ok; anything else (including 0/unknown) is an error.\n\tstatus := \"ok\"","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/shared/platform/importers/helicone.go#L49-L85","documentation":"decodeHelicone tries two shapes: a heliconeEnvelope object with a Data array, then a bare array of heliconeRecords. When both json.Unmarshal attempts fail, the second (bare-array) error is wrapped as 'helicone decode: %w'. The wrapped error is Go's encoding/json detail (e.g. 'invalid character ... looking for beginning of value' or a type mismatch on a record field).","triggerScenarios":"Passing a bare JSON object that is neither shape; passing a JSONL stream; a record where a fixed-type field (e.g. numeric) holds a string, causing unmarshal to fail on []heliconeRecord; empty input bytes; truncated response body saved from a paged API call.","commonSituations":"Saving only the last page of a paginated Helicone export incorrectly; schema change in Helicone API responses changing a field's JSON type; concatenating multiple pages without wrapping them in an array; an auth-error JSON body {\"error\":...} saved instead of data.","solutions":["Read the wrapped json error to identify whether the problem is overall shape or a specific field type","Ensure input is one JSON document: either {\"data\":[...]} or a bare array of records","If a record field changed type upstream, transform it to the expected type before import","Verify the saved export is not an error payload or empty response"],"exampleFix":"// before\nraw := []byte(`{\"error\":\"unauthorized\"}`)\nrows, sum, err := importers.Import(importers.FormatHelicone, raw, opts)\n\n// after\nraw := []byte(`{\"data\":[{\"id\":\"r1\",\"created_at\":\"2026-01-01T00:00:00Z\"}]}`)\nrows, sum, err := importers.Import(importers.FormatHelicone, raw, opts)","handlingStrategy":"validation","validationCode":"func looksLikeHelicone(data []byte) bool {\n\td := bytes.TrimSpace(data)\n\treturn len(d) > 0 && (d[0] == '[' || bytes.Contains(d, []byte(\"\\\"data\\\"\")))\n}","typeGuard":null,"tryCatchPattern":"if _, _, err := importers.Import(importers.FormatHelicone, raw, opts); err != nil { if strings.Contains(err.Error(), \"helicone decode\") { return fmt.Errorf(\"not a Helicone export: %w\", err) } }","preventionTips":["Save the raw API response from Helicone unchanged; do not concatenate pages","Check the export contains \"data\":[ before importing","Automate the export so manual copy/paste truncation cannot occur"],"tags":["go","import","helicone","json","decode"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}