JuliusBrussee/caveman · error
awscreds: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must…
Error message
awscreds: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must both be set
What it means
fromEnv treats a half-configured static key pair as an error rather than silently skipping: if exactly one of AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY is set, the operator clearly intended those credentials, and signing with a pair missing one half is impossible. Only the env spelling is validated here.
Solutions
- Export both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY together
- Check your .env / deployment secret list so both keys are present and mounted
- If you only intended temporary role creds, unset the lone leftover variable so the chain falls through to web identity/container/IMDS
Example fix
// before export AWS_ACCESS_KEY_ID=AKIA... // after export AWS_ACCESS_KEY_ID=AKIA... export AWS_SECRET_ACCESS_KEY=XXXXXXXX
Defensive patterns
Strategy: validation
Validate before calling
id, sec := os.Getenv("AWS_ACCESS_KEY_ID"), os.Getenv("AWS_SECRET_ACCESS_KEY")
if (id == "") != (sec == "") {
return errors.New("set both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or neither")
}
Try / catch
creds, err := provider.Credentials(ctx)
if err != nil {
if strings.Contains(err.Error(), "must both be set") {
// log which var is missing and abort
}
return err
}
Prevention
- Always export the key pair together from the same file/script
- Check orchestrator secret mounts include both keys
- Unset leftover single variables when switching to role-based creds
When it happens
Trigger: Setting AWS_ACCESS_KEY_ID without AWS_SECRET_ACCESS_KEY (or vice versa) in the proxy environment and then resolving credentials via Credentials() → fetch → fromEnv.
Common situations: Partial .env files, secrets injected individually by an orchestrator where one secret failed to mount, shell rc files exporting only one var, copy-pasting only the access key ID.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be set…
- awscreds: no AWS credentials found (env, web identity…
- must not contain a newline
- awscreds: build container credentials request
- awscreds: read container authorization token file
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/30c95ec204b7a188.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/awscreds/awscreds.go:290
return res, nil
}
return nil, errors.New("awscreds: no AWS credentials found (env, web identity, container, IMDS)")
}
func (p *Provider) env(name string) string { return strings.TrimSpace(p.getenv(name)) }
// fromEnv reads static keys. A half-configured pair is an error, not a skip:
// the operator clearly meant to sign as these keys, and falling through would
// silently sign as whatever ambient role the host carries — a different
// principal, bill, and CloudTrail identity — with no disclosure. A lone
// AWS_SESSION_TOKEN is not a pair and does not trigger this.
func (p *Provider) fromEnv(context.Context) (*result, error) {
access, secret := p.env("AWS_ACCESS_KEY_ID"), p.env("AWS_SECRET_ACCESS_KEY")
if access == "" && secret == "" {
return nil, nil
}
if access == "" || secret == "" {
return nil, errors.New("awscreds: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must both be set")
}
return &result{
creds: awssig.Credentials{
AccessKeyID: access,
SecretAccessKey: secret,
SessionToken: p.env("AWS_SESSION_TOKEN"),
},
source: "env",
}, nil
}
// fromWebIdentity implements the EKS IRSA / generic OIDC flow: exchange the
// projected service account token for role credentials at STS. The call is
// unsigned by definition — the token is the proof.
func (p *Provider) fromWebIdentity(ctx context.Context) (*result, error) {
tokenFile, roleARN := p.env("AWS_WEB_IDENTITY_TOKEN_FILE"), p.env("AWS_ROLE_ARN")
if tokenFile == "" || roleARN == "" {
return nil, nilView on GitHub (pinned to 3ee70a1026)