kubernetes/kops · error

error parsing expected RolePolicyDocument for IAMRole %q: %v

Error message

error parsing expected RolePolicyDocument for IAMRole %q: %v

What it means

Find() parses the expected RolePolicyDocument as JSON so it can compare semantically against the actual policy. If the expected content is not valid JSON, the parse error is wrapped with the role name. This is a spec/template problem, not an AWS problem.

Source

Thrown at upup/pkg/fi/cloudup/awstasks/iamrole.go:103

	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)
			}

			if reflect.DeepEqual(actualJson, expectedJson) {
				klog.V(2).Infof("actual RolePolicyDocument was json-equal to expected; returning expected value")
				actualPolicy = expectedPolicy
			}
		}

		actual.RolePolicyDocument = fi.NewStringResource(actualPolicy)
	}
	actual.Tags = mapIAMTagsToMap(r.Tags)

	klog.V(2).Infof("found matching IAMRole %q", aws.ToString(actual.ID))

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Validate the policy JSON locally (jq . policy.json) before applying the cluster spec
  2. Fix the template or manifest producing the invalid JSON (remove comments/commas, ensure variables resolve)
  3. Regenerate the manifest with kops replace/update using a known-good template
  4. Pin the kops version to one consistent with the stored cluster spec

Example fix

// before (invalid JSON with comment)
{"Version":"2012-10-17" /* comment */}
// after
{"Version":"2012-10-17"}
Defensive patterns

Strategy: validation

Validate before calling

// lint expected policy JSON before apply
var buf map[string]interface{}
if err := json.Unmarshal([]byte(expectedPolicy), &buf); err != nil {
    return fmt.Errorf("expected RolePolicyDocument is not valid JSON: %w", err)
}

Type guard

func isJSON(s string) bool { var v interface{}; return json.Unmarshal([]byte(s), &v) == nil }

Prevention

When it happens

Trigger: json.Unmarshal([]byte(expectedPolicy), &expectedJson) fails because the template produced invalid JSON (trailing commas, comments, unquoted keys, truncated output).

Common situations: Hand-edited trust policy template in the cluster spec; Go template placeholders left unresolved; kOps version mismatch generating malformed policy; file truncated in state store.

Related errors


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