{"record":{"id":"c5df80d42e37a422","repo":"JuliusBrussee/caveman","slug":"fix-kind-exceeds-128-bytes","errorCode":null,"errorMessage":"fix kind exceeds 128 bytes","messagePattern":"fix kind exceeds 128 bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/store/learn_outcomes.go","lineNumber":80,"sourceCode":"\t\t}\n\t}\n\tappliedAtTime := learnOutcomeClock().UTC()\n\t// A scan run after the user's edit is post-fix evidence. Prefer newest report\n\t// snapshot strictly older than this plan's scan; use live plan only when no\n\t// older snapshot contains the sink. Missing live sinks may use snapshot only.\n\tsink, beforeSource := beforeSinkForAppliedFix(plan, sinkID, liveSink, appliedAtTime)\n\tif sink == nil {\n\t\treturn AppliedFixRecord{}, fmt.Errorf(\"sink %q not found in current learn plan\", sinkID)\n\t}\n\tfixKind = strings.TrimSpace(fixKind)\n\tif fixKind == \"\" {\n\t\tfixKind = defaultFixKind(*sink)\n\t}\n\tif fixKind == \"\" {\n\t\treturn AppliedFixRecord{}, fmt.Errorf(\"sink %q has no measurable fix kind; pass --fix-kind explicitly\", sinkID)\n\t}\n\tif len(fixKind) > 128 {\n\t\treturn AppliedFixRecord{}, fmt.Errorf(\"fix kind exceeds 128 bytes\")\n\t}\n\tif len(note) > 4096 {\n\t\treturn AppliedFixRecord{}, fmt.Errorf(\"note exceeds 4096 bytes\")\n\t}\n\tappliedAt := appliedAtTime.Format(time.RFC3339)\n\tbeforeEvidence := make(map[string]any, len(sink.Evidence)+1)\n\tfor key, value := range sink.Evidence {\n\t\tbeforeEvidence[key] = value\n\t}\n\tbeforeEvidence[\"before_source\"] = beforeSource\n\tevidence, err := json.Marshal(beforeEvidence)\n\tif err != nil {\n\t\treturn AppliedFixRecord{}, fmt.Errorf(\"encode before evidence: %w\", err)\n\t}\n\t// Fingerprint the edited artifact as it stands NOW — which at\n\t// `caveman learn applied` time is immediately after the approved edit. This\n\t// is the provenance anchor: a later scan re-hashes the same path and can\n\t// state whether the change we proposed is still the change that is there.","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/internal/store/learn_outcomes.go#L62-L98","documentation":"RecordAppliedFix records an applied fix outcome for a sink, and the fixKind string is used as a DB column and report key. The store rejects any fix kind longer than 128 bytes so records stay bounded and comparable. The value may come from the caller or from defaultFixKind; the length check runs after defaulting.","triggerScenarios":"Calling RecordAppliedFix with a fixKind argument (or a sink whose defaultFixKind derives a value) whose UTF-8 length exceeds 128 bytes.","commonSituations":"Passing a whole description or CLI note string as --fix-kind; programmatic callers building fixKind from concatenated labels; upstream schema changes making defaultFixKind produce longer strings.","solutions":["Shorten the fixKind string to 128 bytes or fewer before calling RecordAppliedFix","Check len(fixKind) in the caller and surface a clear CLI validation message before reaching the store","Ensure defaultFixKind on the sink returns a short, stable kind identifier"],"exampleFix":"// before\nrec, err := store.RecordAppliedFix(ctx, sink, userSuppliedKind, note)\n// after\nif len(userSuppliedKind) > 128 {\n    return fmt.Errorf(\"--fix-kind must be at most 128 bytes\")\n}\nrec, err := store.RecordAppliedFix(ctx, sink, userSuppliedKind, note)","handlingStrategy":"validation","validationCode":"if len(fixKind) > 128 { return fmt.Errorf(\"fix kind must be <= 128 bytes, got %d\", len(fixKind)) }","typeGuard":null,"tryCatchPattern":"if rec, err := store.RecordAppliedFix(ctx, sink, fixKind, note); err != nil { if strings.Contains(err.Error(), \"exceeds 128 bytes\") { /* prompt user for shorter --fix-kind */ } }","preventionTips":["Validate --fix-kind length at CLI flag parsing time","Keep fix kinds as short enum-like identifiers, not descriptions","Add a unit test asserting defaultFixKind output stays under 128 bytes"],"tags":["validation","input-length","learn"],"backgroundTag":"value-out-of-range","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"}