{"record":{"id":"4282c3bce25cc6de","repo":"inancgumus/learngo","slug":"record-d-v","errorCode":null,"errorMessage":"record %d: %v","messagePattern":"record (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"logparser/v5/pipe/logcount.go","lineNumber":31,"sourceCode":"// logCount counts the yielded records.\ntype logCount struct {\n\tIterator\n\tn int\n}\n\n// Each yields to the inner iterator while counting the records.\n// Reports the record number on an error.\nfunc (lc *logCount) Each(yield func(Record) error) error {\n\tcount := func(r Record) error {\n\t\tlc.n++\n\t\treturn yield(r)\n\t}\n\n\terr := lc.Iterator.Each(count)\n\n\tif err != nil {\n\t\t// lc.n+1: iterator.each won't call yield on err\n\t\treturn fmt.Errorf(\"record %d: %v\", lc.n+1, err)\n\t}\n\treturn nil\n}\n\n// count returns the last read record number.\nfunc (lc *logCount) count() int {\n\treturn lc.n\n}\n","sourceCodeStart":13,"sourceCodeEnd":40,"githubUrl":"https://github.com/inancgumus/learngo/blob/3c475a78e54336c6255e925ff66b8ef4da6a2ae7/logparser/v5/pipe/logcount.go#L13-L40","documentation":"In v5's pipeline, logCount.Each runs count over every record from the upstream iterator and, if the iterator returned an error, wraps it as 'record %d: %v' using lc.n+1 — the 1-based record number at which iteration stopped (each() doesn't invoke yield when an error occurs, hence n+1). This gives pipeline consumers record-level context for upstream parse errors.","triggerScenarios":"Any upstream error in the pipe (e.g. a malformed record rejected by an earlier stage) surfaces here as 'record N: <underlying error>' when the logCount stage's Each call returns non-nil.","commonSituations":"Corrupt line at position N in a large streamed log, an earlier parsing stage emitting an error mid-stream, or a reader/I/O error propagating through the pipeline.","solutions":["Look at the embedded underlying error for the real cause and fix that record","Log-and-skip bad records in the upstream stage instead of failing the whole pipeline","Include the raw record content in the wrapped message for faster diagnosis"],"exampleFix":"// before\nif err != nil {\n    return fmt.Errorf(\"record %d: %v\", lc.n+1, err)\n}\n// after\nif err != nil {\n    if errors.Is(err, ErrBadRecord) {\n        log.Printf(\"skipping record %d: %v\", lc.n+1, err)\n        return nil // continue processing\n    }\n    return fmt.Errorf(\"record %d: %w\", lc.n+1, err)\n}","handlingStrategy":"try-catch","validationCode":"// Go has no exceptions; guard the pipeline result:\nif err := count(ErrIter); err != nil {\n    var recErr *RecordError\n    if errors.As(err, &recErr) { /* recErr.N identifies the record */ }\n}","typeGuard":"type RecordError struct { N int; Err error }\nfunc (e *RecordError) Error() string { return fmt.Sprintf(\"record %d: %v\", e.N, e.Err) }\nfunc asRecordError(err error) (*RecordError, bool) {\n    var re *RecordError\n    ok := errors.As(err, &re)\n    return re, ok\n}","tryCatchPattern":"if err := pipeline.Run(); err != nil {\n    if re, ok := asRecordError(err); ok {\n        log.Printf(\"failed at record %d: %v\", re.N, re.Err)\n        return nil // or re.Err for the root cause\n    }\n    return err\n}","preventionTips":["Wrap with %w instead of %v so errors.Is/As can unwrap the cause","Skip-and-log recoverable record errors instead of failing the pipeline","Include the raw record data in the wrapped message","Define sentinel errors (ErrBadRecord) to classify failures in the pipeline"],"tags":["go","pipeline","error-wrapping","v5"],"backgroundTag":"pipeline-record-error","analyzedSha":"3c475a78e54336c6255e925ff66b8ef4da6a2ae7","analyzedAt":"2026-09-02T10:14:38.492Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}