Skip to content

Document Timeout() interface / context.DeadlineExceeded pitfall in Go coding guidelines #6424

Description

@fullsend-ai-retro

What happened

In PR #6217, the code agent wrote a new forge.IsTransient(err) function that detects transient errors. It included a check for the interface{ Timeout() bool } interface to identify HTTP client timeouts. However, context.DeadlineExceeded also implements this interface (returning true), so the function incorrectly classified context deadline errors as transient/retryable.

The code agent likely replicated this pattern from the existing isTimeoutError function in internal/forge/github/github.go:295, which uses the same Timeout() bool check but documents that callers must check ctx.Err() first. The new public IsTransient function had no such caller contract.

The review agent (run 32298552946) correctly caught this as a medium-severity logic error. The fix agent added a guard checking errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) before the Timeout() interface check.

What could go better

The code agent could have avoided this bug on the first attempt if the Go coding guidelines documented this well-known Go pitfall. The repo already has a pattern of documenting domain-specific pitfalls — docs/contributing/cel-triggers.md has a "highest-value pitfall" section about synchronize vs synchronized, and docs/contributing/shell-scripting.md has a yq/jq pitfalls section. But docs/contributing/go-code.md has no pitfalls section despite Go having several well-known interface traps.

Confidence: High. The code agent demonstrably replicated the existing isTimeoutError pattern. Adding this pitfall to the guidelines would put it in the code agent's context window when writing Go error-handling code. The repo already has the pattern and infrastructure for pitfall documentation.

Uncertainty: The code agent might still miss documented pitfalls if it doesn't read the relevant guide during code generation. However, the existing pitfall sections in other guides suggest the harness does surface these docs.

Proposed change

Add a "Go pitfalls" section to docs/contributing/go-code.md with the Timeout() bool interface trap as its first entry. The section should explain:

  1. context.DeadlineExceeded implements interface{ Timeout() bool } returning true
  2. Any timeout detection via interface assertion (e.g., if te, ok := err.(interface{ Timeout() bool }); ok && te.Timeout()) must guard against context errors first: if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) { return false }
  3. Reference the forge.IsTransient function as the canonical example of the correct pattern
  4. Explain that context deadline/cancellation errors represent intentional cancellation by the caller, not transient infrastructure failures, so they should never be retried

This follows the existing pattern in cel-triggers.md ("highest-value pitfall") and shell-scripting.md ("yq/jq pitfalls").

Validation criteria

The next code agent run that writes Go timeout/transient error detection should include a context.DeadlineExceeded guard without requiring review agent intervention. Verify by monitoring the next 3-5 code agent PRs in this repo that touch error handling — none should repeat this specific bug pattern.


Generated by retro agent from #6217

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions