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

  1. Inspect the raw AssumeRolePolicyDocument with aws iam get-role --query 'Role.AssumeRolePolicyDocument' and correct invalid percent-encoding
  2. Re-apply the expected trust policy from the kOps spec (kops update cluster) to overwrite the malformed document
  3. If a proxy/middle layer is rewriting the document, bypass or fix it
  4. 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

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


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/8e7e71212e8834cb. Report an issue: GitHub.