fix(xerrors): do not silently drop foreign collected errors in Collector.Collect#424
Merged
Conversation
…tor.Collect Collector.Collect previously short-circuited on any *collected error and returned without storing or counting it. The branch was designed for the case where the collected error originates from one of c's own descendant collectors (so it is reachable via tree auto-join), but it also matched foreign *collected values produced by unrelated, parser-local fail-fast collectors (e.g. confgen sheetParser.sheetCollector created via xerrors.NewCollector(1)). When such a foreign collected error was passed to an upstream sheetCollector, the error was neither appended to errs nor counted, HasErrors() stayed false, and Join() returned nil — silently swallowing real diagnostics. Tighten the short-circuit to only fire when the collected error's origin shares the same root as c (i.e. belongs to the same collector tree built via NewChild). Foreign collected errors now fall through to the ordinary path and are stored and counted on c, so they surface through HasErrors()/Join() as expected. Update tests: - Replace TestCollected_CollectSkipsCollectedError / TestCollected_CollectSkipsWrappedCollectedError with positive assertions that foreign (wrapped) collected errors are preserved. - TestCollected_CrossSubtreeCollection still passes: same-tree siblings retain the no-double-count behavior.
|
The latest Buf updates on your PR. Results from workflow Buf CI / buf (pull_request).
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #424 +/- ##
==========================================
+ Coverage 74.95% 75.02% +0.06%
==========================================
Files 88 88
Lines 9408 9416 +8
==========================================
+ Hits 7052 7064 +12
+ Misses 1784 1782 -2
+ Partials 572 570 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Add tests covering the previously-uncovered lines in Collector.Collect's same-tree short-circuit and the sameTreeAs helper: - CollectSameTreeWrappedCollectedRecordsOuterWM: a WrapKV'd same-tree collected error records its outer withMessage on the origin collector (lines 87-90) and Join() re-applies the fields. - CollectSameTreeCollectedWhenFullReturnsJoin: when the receiver is full, collecting a same-tree collected marker returns Join() immediately instead of nil (line 93). - SameTreeAs_Nil: sameTreeAs returns false for nil receiver/argument (line 147), the branch unreachable from Collect's nil guards. Patch coverage: 57.1% -> 100% of changed lines. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
wenchy
approved these changes
Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
xerrors.Collector.Collectshort-circuited on any*collectederror:This branch was designed for the case where the incoming error comes from one of
c's own descendant collectors — that error is already reachable from the root via tree auto-join, so re-counting it oncwould produce duplicates.However, the same branch also matched foreign
*collectedvalues: errors produced by an unrelated, parser-local fail-fast collector that is not a child ofc. The canonical example in this repo:confgen.NewExtendedSheetParsercreates its ownxerrors.NewCollector(1)for in-sheet fail-fast diagnostics (internal/confgen/parser.go:333).protogen.parseEnumTypeSheet(modeMODE_ENUM_TYPE_MULTI) calls into confgen and the sheet parser hits an error, confgen's local collector callsJoin()and returns a*collected{origin: parserLocalCol}up the call chain.protogen.go:716doessheetCollector.Collect(xerrors.WrapKV(blockErr, KeyBookName, ..., KeySheetName, ...)).sheetCollectoris built viabookCollector.NewChild(...)and has no parent relationship withparserLocalCol, so the short-circuit was firing on a foreign origin.Net effect:
sheetCollector.errsnor counted.outerWMwas written onto the foreign collector (whichsheetCollector.Join()never visits).sheetCollector.HasErrors()stayedfalse,Join()returnednil.parseEnumType/parseStructType) was silently swallowed and the tool exited 0 with no output.Fix
Tighten the short-circuit so it only fires when the collected error's origin is part of
c's own collector tree (shares the same root reachable via theparentchain).Two small helpers (
root,sameTreeAs) are added toCollector. They are pure parent-chain walks, no locks needed.Semantics after the fix
Collect(err)whereerris*collectedwith originoc:ocis in the same collector tree asc(shares root)WrapKVfields onocand return; do not double-count.ocis foreign (different tree, e.g. parser-local fail-fast collector)c.errs, bump every ancestor's counter.HasErrors()andJoin()now surface it.Tests
Renamed two tests whose assertions encoded the buggy "silently drop foreign collected" behavior:
TestCollected_CollectSkipsCollectedError→TestCollected_CollectForeignCollectedIsNotDroppedTestCollected_CollectSkipsWrappedCollectedError→TestCollected_CollectForeignWrappedCollectedIsNotDroppedBoth now assert that the foreign (and
WrapKV-wrapped foreign) collected error survivesCollectand shows up inJoin().TestCollected_CrossSubtreeCollectionkeeps its original assertion (same-tree siblings betweenouterChild/innerChildunderdocChild): outer must not re-count an inner sibling's*collected. The new same-tree predicate covers this case unchanged.All other
internal/x/xerrorstests pass without modification.Verification
Compatibility