{"record":{"id":"48d3261c8b198567","repo":"JuliusBrussee/caveman","slug":"sanitize-row-d-w","errorCode":null,"errorMessage":"sanitize row %d: %w","messagePattern":"sanitize row (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/importers/importers.go","lineNumber":103,"sourceCode":"\t\trows, err = parseLangfuse(data, opts)\n\tcase FormatHelicone:\n\t\trows, err = parseHelicone(data, opts)\n\tcase FormatGeneric:\n\t\trows, err = parseGeneric(data, opts)\n\tdefault:\n\t\t// fail-closed: unknown formats are an error, never a silent pass-through.\n\t\treturn nil, Summary{}, fmt.Errorf(\"unknown import format %q: supported formats are otlp, caveman-jsonl, langfuse, helicone, generic\", format)\n\t}\n\tif err != nil {\n\t\treturn nil, Summary{}, err\n\t}\n\tfor i := range rows {\n\t\tif len(rows[i].EventsJSON) > telemetry.MaxEventsBytes {\n\t\t\treturn nil, Summary{}, fmt.Errorf(\"sanitize row %d: events exceed %d bytes\", i, telemetry.MaxEventsBytes)\n\t\t}\n\t\tsanitized, sanitizeErr := telemetry.SanitizeAttributes(rows[i].Attributes)\n\t\tif sanitizeErr != nil {\n\t\t\treturn nil, Summary{}, fmt.Errorf(\"sanitize row %d: %w\", i, sanitizeErr)\n\t\t}\n\t\trows[i].Attributes = sanitized\n\t}\n\treturn rows, Summary{Format: format, RowCount: len(rows)}, nil\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\n// chTimeLayout is the ClickHouse DateTime64 textual layout the gateway writer\n// uses; importers must produce the same shape (\"2006-01-02 15:04:05.000\").\nconst chTimeLayout = \"2006-01-02 15:04:05.000\"\n\n// applyScope stamps the authenticated org/project onto a span and fills the\n// honest defaults that the spans schema expects for non-null operation. It is\n// called for EVERY produced span so the uploaded file can never set org/project.\nfunc applyScope(sp *Span, opts Options) {","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/shared/platform/importers/importers.go#L85-L121","documentation":"Every row's Attributes must pass telemetry.SanitizeAttributes before import completes; any error it returns is wrapped with the row index. Sanitization enforces attribute-level constraints (size, count, key/value validity) defined in shared/platform/telemetry, so the wrapped error text tells you the specific attribute violation on that row. Like 1188, one bad row fails the whole import.","triggerScenarios":"An attribute value exceeding the per-attribute byte limit (e.g. a full prompt stored as an attribute); invalid attribute keys (empty or control characters); attribute maps exceeding the sanctioned count; non-UTF8 bytes in values.","commonSituations":"GenAI traces that smuggle request bodies into attributes instead of events; third-party OTLP exporters adding huge resource attributes; binary or binary-encoded values placed in string attributes.","solutions":["Read the wrapped error to identify the exact attribute constraint violated on the indexed row","Move oversized values from attributes to a proper storage side-channel, or truncate them pre-import","Sanitize/normalize attribute keys and values in your own pipeline before calling Import","Re-run import after fixing; the row index in the message points at the offending record"],"exampleFix":"// before\nattrs := map[string]string{\"prompt\": giantPromptText}\nsp.Attributes = attrs\n\n// after\nconst maxAttr = 8 << 10\nif len(giantPromptText) > maxAttr {\n    giantPromptText = giantPromptText[:maxAttr]\n}\nattrs := map[string]string{\"prompt\": giantPromptText}\nsp.Attributes = attrs","handlingStrategy":"try-catch","validationCode":"if _, err := telemetry.SanitizeAttributes(sp.Attributes); err != nil { /* fix attributes before import */ }","typeGuard":null,"tryCatchPattern":"rows, sum, err := importers.Import(format, data, opts)\nif err != nil {\n\tif i := strings.Index(err.Error(), \"sanitize row\"); i >= 0 {\n\t\tlog.Printf(\"attribute violation on row %d: %v\", rowIndexFrom(err), err)\n\t}\n\treturn err\n}","preventionTips":["Pre-sanitize attributes with telemetry.SanitizeAttributes before constructing Spans","Keep large payloads out of attributes; use dedicated event/storage fields","Enforce attribute key/value length limits in your own emitters"],"tags":["go","import","telemetry","sanitization","attributes"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}