Aws sdk error handling canonical
Skill esaldgut/ai-native-engineering-workspace/global-skills/aws-go/aws-sdk-error-handling-canonical
AI-native engineering workspace — 42 Claude Code agent skills, platform-base workflow docs, and a freshness system that re-verifies each pattern against vendor docs.
npx -y skills add esaldgut/ai-native-engineering-workspace --skill aws-sdk-error-handling-canonicalAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Handle AWS SDK Go v2 errors the canonical way — errors.As against typed/modeled errors and the smithy.APIError interface — and NEVER strings.Contains(err.Error(), "...") to silence or branch on an SDK error. String-matching error text breaks silently across SDK upgrades and, worse, masks a deeper bug: if a "silenced" error fires on every normal invocation, the API is being called in a context AWS does not support (e.g. AdminLinkProviderForUser in PreSignUp). Use when writing or reviewing any error-handling branch around an AWS SDK Go v2 call, especially one that treats an error as "idempotent / already exists / edge case OK."
SKILL.md
7.8 KB, as published. Nobody here has run it
Canonical AWS SDK Go v2 error handling
The AWS SDK for Go v2 contracts on error type identity, not error message text. The
official guide is
explicit: errors implement Unwrap, and you use errors.As to reach the typed layers. Error
messages are layered (a wrap chain) and AWS does not guarantee their stability across SDK or
service versions — so strings.Contains(err.Error(), "...") is undefined behavior that compiles
today and breaks on the next release with no signal.
When to invoke
- Writing any
if err != nilbranch around an AWS SDK Go v2 call that does something other than return the error — silences it, treats it as "already exists / idempotent," or routes on it. - Reviewing code that contains
strings.Contains(err.Error(), ...),strings.HasPrefix(err.Error(), ...), or aswitchovererr.Error()against an AWS call. - Cross-service handlers that need generic error-code routing.
Announce on invoke: "Using aws-sdk-error-handling-canonical to branch on typed errors via errors.As + smithy.APIError, not on error text."
The three typed layers (most specific first)
- Operation-specific modeled error — e.g.
*types.BucketAlreadyExistsfor S3CreateBucket,*types.UsernameExistsException/*types.AliasExistsExceptionfor Cognito. Most precise; use for business logic. Lives in each service's.../service/<name>/typespackage. smithy.APIError(interface) — covers both modeled and un-modeled responses. ExposesErrorCode() string,ErrorMessage() string,ErrorFault() ErrorFault(andErrorFault.String()). Use for generic, cross-service code-based routing.smithy.OperationError— wraps everything with service + operation context (Service(),Operation(),Unwrap()). Use for centralized logging.
The hard rule: never string-match SDK error text to silence
The anti-pattern isn't just fragile — it's a misdiagnosis detector. If you find yourself writing:
// WRONG — fragile AND a symptom of a deeper bug
if err != nil && strings.Contains(err.Error(), "Already found an entry for username") {
return nil // "idempotent, the link already exists" — NO.
}
…and that branch fires on every normal invocation, the silence is hiding the real fact: the API
is being invoked in a context AWS does not support. The canonical instance —
cognito-idp:AdminLinkProviderForUser called inside the PreSignUp trigger — returns
AliasExistsException ("Already found an entry for username") on the first federated sign-up
because the user does not exist yet. It is not idempotency; it is a documented Cognito
limitation. The fix is not a stronger string match — it's reading the doc and moving the call to
PostConfirmation (see related skill). String-silencing would have buried that signal.
Canonical example
import (
"context"
"errors"
"log"
"github.com/aws/aws-sdk-go-v2/service/myservice"
mytypes "github.com/aws/aws-sdk-go-v2/service/myservice/types"
"github.com/aws/smithy-go"
)
func DoThing(ctx context.Context, c *myservice.Client, id string) error {
_, err := c.DescribeThing(ctx, &myservice.DescribeThingInput{Id: &id})
if err == nil {
return nil
}
// 1) Preferred: typed modeled error — "absence is legitimately OK" handled by TYPE.
var nf *mytypes.ResourceNotFoundException
if errors.As(err, &nf) {
log.Printf("thing %s not found", id)
return nil
}
// 2) Generic fallback: code-based routing for any AWS error.
var ae smithy.APIError
if errors.As(err, &ae) {
log.Printf("aws error code=%s msg=%s fault=%s",
ae.ErrorCode(), ae.ErrorMessage(), ae.ErrorFault().String())
}
return err
}
For batch/cross-service logging, add the operation context:
var oe *smithy.OperationError
if errors.As(err, &oe) {
log.Printf("failed service=%s operation=%s: %v", oe.Service(), oe.Operation(), oe.Unwrap())
}
Anti-pattern to detect (greppable)
strings.Contains(err.Error(), ...),strings.HasPrefix(err.Error(), ...), orerr.Error() == "..."anywhere near an AWS SDK call — reject in review.- Any branch that returns
nil(success) on an AWS error matched by text. - A silenced error whose message you copied from a stack trace — that's the tell that you're matching text, not type.
Decision aid
- Need "this specific error means X" (already exists, not found, conflict)? →
errors.Aswith the service's modeled*types.XxxException. - Need "any AWS error with code C" across N services? →
errors.As(err, &ae)then compareae.ErrorCode(). - A silence fires on every happy-path call? → stop. Read the AWS doc for that API in that context. The error is telling you the API isn't supported there.
Related skills
global-skills/aws-go/verify-provider-api-supports-property/SKILL.md— theAdminLinkProviderForUser-in-PreSignUp case is the textbook "promised property the provider API doesn't support" — verify the method before promising atomic account-linking.global-skills/aws-go/aws-sdk-go-v2-version-policy/SKILL.md— modeledtypespackages live under the service package you chose; pick that deliberately first.
Sources
- Handling Errors in the AWS SDK for Go V2 — uses
errors.Aswith*types.BucketAlreadyExists,smithy.APIError,smithy.OperationError - smithy.APIError / OperationError / ErrorFault · errors.As
- Cognito AdminLinkProviderForUser API ref · re:Post — "Already found an entry for username"
Last verified: 2026-06-03 against the AWS SDK Go v2 error-handling guide (live), which models
the canonical pattern as errors.As against *types.BucketAlreadyExists and the smithy.APIError
interface (ErrorCode()/ErrorMessage()/ErrorFault().String()); the
AdminLinkProviderForUser/PreSignUp limitation re-confirmed on AWS re:Post.
Re-check after: AWS SDK Go v2 major / CDK CLI major, or by 2026-09-03. Decay risk: low
(typed-error contract is stable; the message text it replaces is what churns).
Found a drift? Run /skill-pattern-freshness-audit aws-go.