kubernetes/kops · error
error parsing AssumeRolePolicyDocument for IAMRole %s: %v
Error message
error parsing AssumeRolePolicyDocument for IAMRole %s: %v
What it means
AWS returns the role's trust (assume-role) policy URL-encoded. Find() unescapes it before JSON comparison; if QueryUnescape fails, the error is wrapped with the role name. This is nearly always caused by malformed percent-encoding in the stored policy document.
Source
Thrown at upup/pkg/fi/cloudup/awstasks/iamrole.go:90
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("error getting role: %v", err)
}
r := response.Role
actual := &IAMRole{}
actual.ID = r.RoleId
actual.Name = r.RoleName
if r.PermissionsBoundary != nil {
actual.PermissionsBoundary = r.PermissionsBoundary.PermissionsBoundaryArn
}
if r.AssumeRolePolicyDocument != nil {
// The AssumeRolePolicyDocument is URI encoded (?)
actualPolicy := *r.AssumeRolePolicyDocument
actualPolicy, err = url.QueryUnescape(actualPolicy)
if err != nil {
return nil, fmt.Errorf("error parsing AssumeRolePolicyDocument for IAMRole %s: %v", *e.Name, err)
}
// The RolePolicyDocument is reformatted by AWS
// We parse both as JSON; if the json forms are equal we pretend the actual value is the expected value
if e.RolePolicyDocument != nil {
expectedPolicy, err := fi.ResourceAsString(e.RolePolicyDocument)
if err != nil {
return nil, fmt.Errorf("error reading expected RolePolicyDocument for IAMRole %q: %v", aws.ToString(e.Name), err)
}
expectedJson := make(map[string]interface{})
err = json.Unmarshal([]byte(expectedPolicy), &expectedJson)
if err != nil {
return nil, fmt.Errorf("error parsing expected RolePolicyDocument for IAMRole %q: %v", aws.ToString(e.Name), err)
}
actualJson := make(map[string]interface{})
err = json.Unmarshal([]byte(actualPolicy), &actualJson)
if err != nil {
return nil, fmt.Errorf("error parsing actual RolePolicyDocument for IAMRole %q: %v", aws.ToString(e.Name), err)View on GitHub (pinned to 4c8573c808)
Solutions
- Inspect the raw AssumeRolePolicyDocument with aws iam get-role --query 'Role.AssumeRolePolicyDocument' and correct invalid percent-encoding
- Re-apply the expected trust policy from the kOps spec (kops update cluster) to overwrite the malformed document
- If a proxy/middle layer is rewriting the document, bypass or fix it
- Re-run reconciliation after the policy is normalized
Defensive patterns
Strategy: validation
Validate before calling
// validate unescaping works before processing
actualPolicy := *r.AssumeRolePolicyDocument
decoded, err := url.QueryUnescape(actualPolicy)
if err != nil { return fmt.Errorf("malformed percent-encoding in AssumeRolePolicyDocument: %w", err) } Type guard
func isValidEncodedPolicy(s string) bool {
_, err := url.QueryUnescape(s)
return err == nil
} Prevention
- Never hand-edit trust policies with raw percent sequences
- Re-apply policies via kOps so AWS normalizes encoding
- Validate stored documents decode cleanly after any out-of-band change
- Pin tooling versions that write policy documents
When it happens
Trigger: url.QueryUnescape(actualPolicy) returns an error, i.e. the AssumeRolePolicyDocument contains invalid escape sequences like %zz that AWS (or an intermediary) stored unexpectedly.
Common situations: Manual mutation of the trust policy via CLI/API producing non-standard encoding; proxy or state-store corruption; unusual characters in role session names inside the policy.
Related errors
- error parsing expected RolePolicyDocument for IAMRole %q: %v
- error parsing actual RolePolicyDocument for IAMRole %q: %v
- error updating IAMRole: %v
- from AWS S3 GetBucketPolicyStatusWithContext: %w
- IP version is incorrect
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/8e7e71212e8834cb.
Report an issue: GitHub.