Skip to content

Fix error counter keying on dynamic error messages#182

Open
andrewwormald wants to merge 3 commits intomainfrom
fix/error-counter-key-stability
Open

Fix error counter keying on dynamic error messages#182
andrewwormald wants to merge 3 commits intomainfrom
fix/error-counter-key-stability

Conversation

@andrewwormald
Copy link
Collaborator

@andrewwormald andrewwormald commented Mar 10, 2026

Problem

Error counter uses err.Error() as part of the map key. Errors with dynamic content (timestamps, IDs) create unique keys, so PauseAfterErrCount threshold is never reached. Also, zeroed keys are never pruned, leaking memory.

Why

Records that should be paused after N errors retry forever — the safety net silently doesn't work.

Fix

Key only on labels (processName + runID) which are stable. Use delete() instead of zeroing on Clear().

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Updated error counting interface for improved label handling consistency and clearer separation of primary and additional label parameters.
    • Optimised key construction for error tracking to ensure stable and predictable counter identification.
    • Adjusted counter clearing behaviour to completely remove entries rather than reset values.
  • Tests

    • Expanded test coverage with new scenarios for cross-error label sharing, independent label tracking, and clearing operations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

The ErrorCounter interface methods (Add, Count, Clear) were refactored to replace variadic labels with an explicit first label parameter and optional extras. The implementation now uses a new makeKey helper function that constructs stable keys from label and extras only, excluding the error message from key composition. The Clear method now deletes keys from storage rather than resetting counts. Tests were reorganised with new cases covering different errors with identical labels, key removal verification, and separate label combination isolation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • ScaleneZA
  • echarrod

Poem

🐰 Whiskers twitching with delight

Labels trimmed to just one way,
Extras dance in neat array,
Keys now stable, errors cast,
Clear removes what's in the past! 🔑✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing error counter keying by removing dynamic error messages from the key construction logic and using stable labels instead.
Description check ✅ Passed The description is directly related to the changeset, clearly explaining the problem (dynamic error messages in keys), the impact (safety threshold not reached), and the fix (key only on stable labels, use delete instead of zeroing).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/error-counter-key-stability

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

andrewwormald and others added 2 commits March 10, 2026 10:04
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous approach silently dropped the error message from the key
but kept labels optional. This meant callers without labels would share
a single global counter — a worse behaviour change.

Now the interface requires at least one label (label string, extras ...string),
making the contract explicit. All existing callers already pass two labels
(processName, runID) so no call sites change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai coderabbitai bot requested review from ScaleneZA and echarrod March 10, 2026 16:46
@sonarqubecloud
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/errorcounter/errorcounter.go`:
- Around line 47-51: The makeKey function currently joins label and extras with
"-" which can produce ambiguous keys (e.g., ("process-a","run-1") vs
("process","a","run-1")); update makeKey to encode segment boundaries
unambiguously (for example by prefixing lengths or using a separator-and-escape
scheme or null-byte delimiter) so each segment is recoverable and collisions are
impossible, and ensure any code that relies on makeKey (e.g., Clear or lookup
paths) continues to use the new encoding; also add a regression test that
constructs two colliding tuples like ("process-a","run-1") and
("process","a","run-1") and verifies they map to distinct keys and that Clear
only removes the intended entry.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b794c086-32b3-40b3-92b1-cc3fc50473bf

📥 Commits

Reviewing files that changed from the base of the PR and between f4d926f and 33333bc.

📒 Files selected for processing (3)
  • errors.go
  • internal/errorcounter/errorcounter.go
  • internal/errorcounter/errorcounter_test.go

Comment on lines +47 to +51
func makeKey(label string, extras []string) string {
if len(extras) == 0 {
return label
}
return label + "-" + strings.Join(extras, "-")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use an unambiguous key encoding here.

Line 51 can collide across different label tuples, for example ("process-a", "run-1") and ("process", "a", "run-1") both become process-a-run-1. That will merge unrelated counters and let Clear remove the wrong entry, which undermines the safety net this PR is fixing. Please encode segment boundaries explicitly instead of "-"-joining labels, and add a regression test for one of these collision cases.

Proposed fix
 import (
+	"strconv"
 	"strings"
 	"sync"
 )
@@
 func makeKey(label string, extras []string) string {
-	if len(extras) == 0 {
-		return label
-	}
-	return label + "-" + strings.Join(extras, "-")
+	parts := make([]string, 0, len(extras)+1)
+	parts = append(parts, label)
+	parts = append(parts, extras...)
+
+	var b strings.Builder
+	for _, part := range parts {
+		b.WriteString(strconv.Itoa(len(part)))
+		b.WriteByte(':')
+		b.WriteString(part)
+		b.WriteByte('|')
+	}
+
+	return b.String()
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/errorcounter/errorcounter.go` around lines 47 - 51, The makeKey
function currently joins label and extras with "-" which can produce ambiguous
keys (e.g., ("process-a","run-1") vs ("process","a","run-1")); update makeKey to
encode segment boundaries unambiguously (for example by prefixing lengths or
using a separator-and-escape scheme or null-byte delimiter) so each segment is
recoverable and collisions are impossible, and ensure any code that relies on
makeKey (e.g., Clear or lookup paths) continues to use the new encoding; also
add a regression test that constructs two colliding tuples like
("process-a","run-1") and ("process","a","run-1") and verifies they map to
distinct keys and that Clear only removes the intended entry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants