Repository navigation
chore: Alias pkg/errors as pkgerrors, enable errorlint, and use stdlib errors where it suffices - #133
Merged
Merged
Conversation
github.com/pkg/errors was imported unaliased in all 29 files that use it, so the bare identifier errors meant pkg/errors everywhere and the standard library errors package was unreachable without a rename. The package a reader sees as errors was not the one they would expect. This adopts the convention upstream Cluster API uses. CAPI v1.14.2 imports pkg/errors in 278 files and aliases it as pkgerrors at every one of those sites, which frees the bare errors for the standard library. Doing the same here keeps us aligned with upstream rather than diverging from it. Migrating off pkg/errors entirely was considered and rejected. CAPI requires it directly, so it stays in our module graph as an indirect dependency whether or not we import it, and upstream shows no sign of moving: v1.14.2 still has 901 Wrapf, 415 Wrap, 451 Errorf and 317 New calls. A rewrite would mean ~191 behaviour-bearing call sites, including a few where Wrap(nil) returning nil is load-bearing, for no dependency reduction and a permanent style split with upstream. The rename itself is a pure identifier substitution: same package, same functions, no behaviour change. Inverting it on the working tree reproduces the previous revision byte for byte, and the per-function call counts are unchanged at 54 New, 49 Wrap, 42 Errorf, 39 Wrapf, 5 Is, 1 Cause and 1 As. The apierrors and kerrors aliases in the seven files that also import an apimachinery errors package are untouched. An importas entry pins the alias, so a future unaliased import fails lint instead of quietly reintroducing the shadow. errorlint is enabled alongside it and already passes with no findings; it guards the fmt.Errorf %w sites that pkg/cloud/instance.go already has, and anything added later. Note it only inspects fmt.Errorf, so it cannot see pkgerrors.Errorf or Wrapf. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… sentinel With pkg/errors now aliased as pkgerrors, the bare errors identifier is free for the standard library. These seven sites are the ones where pkg/errors adds nothing, so they move over. This mirrors upstream Cluster API, which uses stdlib errors.New, errors.Is and errors.As alongside pkgerrors. pkg/errors' Is and As are thin forwarders to the standard library, so the six call sites in cloudstackmachine_controller.go, pkg/cloud/instance.go, pkg/cloud/client.go and pkg/metrics/metrics.go call exactly the same function before and after. cloud.ErrNotFound is returned bare and never wrapped, and every comparison against it is by identity, so stdlib errors.New is equivalent. It also drops a stack trace that nothing ever formatted. pkg/metrics/metrics.go had errors.As as its only pkg/errors use, so it no longer imports pkg/errors at all. The other three files keep it for Wrap, Wrapf, Errorf and New. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Merged
3 tasks done
FarnazBGH
approved these changes
Sep 15, 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.
Summary
github.com/pkg/errorswas imported unaliased in all 29 files that use it, so the bare identifiererrorsmeant pkg/errors everywhere and the standard libraryerrorspackage was unreachable without a rename. The package a reader sees aserrorswas not the one they would expect.This adopts the convention upstream Cluster API uses, rather than diverging from it.
Two commits:
b79dc03— the alias rename plus lint configa261495— the seven sites where stdliberrorssufficesWhy alias rather than migrate off pkg/errors
The obvious move is to replace pkg/errors with
fmt.Errorf/%w. I looked into that and it does not hold up:sigs.k8s.io/cluster-api@v1.14.2requiresgithub.com/pkg/errorsdirectly. Dropping every CAPC import only demotes it to// indirect; it stays in the build regardless.Wrapf, 415Wrap, 451Errorfand 317Newcalls. What it did do is standardise on the aliaspkgerrorsat all 281 import sites, freeing bareerrorsfor the standard library — which it then uses forNew,IsandAs. That is exactly what this PR does.A full rewrite would mean ~191 behaviour-bearing call sites for no dependency reduction and a permanent style split with upstream. It would also have to handle sites where
errors.Wrap(nil, ...)returning nil is load-bearing —pkg/cloud/isolated_network.go:723wraps a raw call result and:891wraps an unguardederr; a naivefmt.Errorf("...: %w", ...)there would make every successful isolated-network reconcile return a non-nil error.The rename is provably mechanical
Same package, same functions, no behaviour change. Two checks back that up:
New, 49Wrap, 42Errorf, 39Wrapf, 5Is, 1Cause, 1As— 191 before, 191 after.The
apierrorsandkerrorsaliases in the seven files that also import an apimachinery errors package are untouched.Lint config
importasgains agithub.com/pkg/errors→pkgerrorsentry, so a future unaliased import fails lint instead of quietly reintroducing the shadow.errorlintis enabled. It already passes with zero findings on the current tree, so it costs nothing today; it guards thefmt.Errorf/%wsitespkg/cloud/instance.goalready has and anything added later. Worth knowing: it only inspectsfmt.Errorf, so it cannot seepkgerrors.Errorf/Wrapf.Second commit: stdlib where it suffices
Seven sites where pkg/errors adds nothing:
errors.Isand oneerrors.Ascalls. pkg/errors' versions are thin forwarders to the standard library, so these call the identical function before and after.cloud.ErrNotFound. It is returned bare, never wrapped, and every comparison is by identity, so stdliberrors.Newis equivalent — and drops a stack trace nothing ever formatted.pkg/metrics/metrics.gohaderrors.Asas its only pkg/errors use, so it no longer imports pkg/errors at all (29 → 28 files).Found while surveying — deliberately NOT in this PR
Real issues, none caused by this work. Filing separately; flagging here so they are not lost:
test/e2e/common.go:406doesFail(fmt.Sprintf("Invalid secret: %+v, %s, %s, %s", secret.Data, apiURL, apiKey, secretKey))— printing the whole secret map plus the CloudStack api-key and secret-key in cleartext into CI logs on the invalid-secret path. Worth fixing regardless of anything here.pkg/cloud/zone.go:34and:36append the identicalWrapf(err, "could not get Zone ID from %v", ...)twice, with the metrics call between them — a copy-paste slip that duplicates the message in the multierror output.%+von an error that is never wrapped.internal/controllers/cloudstackmachine_controller.go:214usesErrorf("failed to reconcile LB attachment: %+v", err).Errorfdoes not wrap, soerrors.Is/Asalready cannot see through it.Test plan
make buildmake lint— 0 issues, 43 active linters including the two addedmake test— all ginkgo suites plus theinternal/controllersenvtest suite.pkg/cloudmatters most here: it asserts on exact error strings (instance_test.gousesMatchErrorwith literals,zone_test.go:73-75encodes the": "wrap separator), so a passing run confirms no message shapes movedgo vet -tags e2e ./...intest/e2e— not covered bymake lint, which excludestest/🤖 Generated with Claude Code