Skip to content

[linter-miner] feat(linters): add contextcancelnotdeferred linter #35280

Description

@github-actions

Summary

Adds a new contextcancelnotdeferred linter that reports context cancel functions returned by context.WithCancel, context.WithTimeout, or context.WithDeadline that are called directly rather than via defer.

What it catches

Failing to defer cancel() immediately after obtaining a cancel function means any early return or panic between the context creation and the direct cancel() call will leak the context and associated goroutines.

// ❌ Flagged — cancel not deferred
ctx, cancel := context.WithTimeout(parent, 5*time.Second)
result, err := doWork(ctx)
cancel() // ← should be: defer cancel()

// ✅ Safe — cancel is deferred
ctx, cancel := context.WithTimeout(parent, 5*time.Second)
defer cancel()
result, err := doWork(ctx)

Evidence

Code-pattern scanner found this pattern in the codebase:

  • pkg/cli/mcp_inspect_mcp.go:196–210listToolsCtx, cancel := context.WithTimeout(...) followed by cancel() called inline after the operation, with no defer
  • pkg/workflow/safe_outputs_actions.go:291–294 — same pattern inside a goroutine

Files changed

  • pkg/linters/contextcancelnotdeferred/contextcancelnotdeferred.go — analyzer implementation
  • pkg/linters/contextcancelnotdeferred/contextcancelnotdeferred_test.go — analysistest-based tests
  • pkg/linters/contextcancelnotdeferred/testdata/src/contextcancelnotdeferred/contextcancelnotdeferred.go — test fixtures with // want annotations
  • cmd/linters/main.go — registers the new analyzer

Implementation notes

  • Skips test files via filecheck.IsTestFile
  • Does not descend into function literals (closures have their own scope)
  • Only flags when a direct cancel() call exists and no defer cancel() is present in the same function

Generated by Linter Miner · sonnet46 5.4M ·

  • expires on Jun 3, 2026, 6:30 PM UTC

Note

This was originally intended as a pull request, but the git push operation failed.

Workflow Run: View run details and download bundle artifact

The bundle file is available in the agent artifact in the workflow run linked above.

To create a pull request with the changes:

# Download the artifact from the workflow run
gh run download 26529852156 -n agent -D /tmp/agent-26529852156

# Fetch the bundle into a temporary ref, then update the local branch
git fetch /tmp/agent-26529852156/aw-linter-miner-context-cancel-not-deferred.bundle refs/heads/linter-miner/context-cancel-not-deferred:refs/bundles/create-pr-linter-miner-context-cancel-not-deferred-35185a4255b75a58-164e95e3
git update-ref refs/heads/linter-miner/context-cancel-not-deferred-35185a4255b75a58 refs/bundles/create-pr-linter-miner-context-cancel-not-deferred-35185a4255b75a58-164e95e3
git checkout linter-miner/context-cancel-not-deferred-35185a4255b75a58
# Ensure the working tree matches the updated branch
git reset --hard
# Remove the temporary bundle ref
git update-ref -d refs/bundles/create-pr-linter-miner-context-cancel-not-deferred-35185a4255b75a58-164e95e3

# Push the branch to origin
git push origin linter-miner/context-cancel-not-deferred-35185a4255b75a58

# Create the pull request
gh pr create --title '[linter-miner] feat(linters): add contextcancelnotdeferred linter' --base main --head linter-miner/context-cancel-not-deferred-35185a4255b75a58 --repo github/gh-aw

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions