kubernetes/kops · error

additionalPolicy %q is invalid: %v

Error message

additionalPolicy %q is invalid: %v

What it means

In buildIAMTasks, the per-role additional IAM policy from spec.additionalPolicies (keyed by role, e.g. node, control-plane, bastion) is parsed via buildPolicy. If the policy document is not parseable IAM policy JSON, the build aborts with "additionalPolicy <roleKey> is invalid" plus the parse error.

Source

Thrown at pkg/model/awsmodel/iam.go:370

					if key == "master" {
						key = "control-plane"
					}
					additionalPolicy = b.Cluster.Spec.AdditionalPolicies[key]
				}

				additionalPolicyName := "additional." + iamName

				t := &awstasks.IAMRolePolicy{
					Name:      new(additionalPolicyName),
					Lifecycle: b.Lifecycle,

					Role: iamRole,
				}

				if additionalPolicy != "" {
					p, err := b.buildPolicy(additionalPolicy)
					if err != nil {
						return fmt.Errorf("additionalPolicy %q is invalid: %v", roleKey, err)
					}

					policy, err := p.AsJSON()
					if err != nil {
						return fmt.Errorf("error building IAM policy: %w", err)
					}

					t.PolicyDocument = fi.NewStringResource(policy)
				} else {
					t.PolicyDocument = fi.NewStringResource("")
				}

				c.AddTask(t)
			}
		}
	}

	return nil

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Validate the policy text with a JSON parser (`jq`) and fix the syntax reported in the wrapped error.
  2. Ensure each statement object is inside a Statement array with valid Effect/Action/Resource types.
  3. If templating the policy, render it and inspect the final string stored in the cluster spec.

Example fix

// before
spec:
  additionalPolicies:
    node: '{"Version":"2012-10-17","Statement":{"Effect":"Allow","Action":"ec2:Describe*","Resource":"*"}}'
// after
spec:
  additionalPolicies:
    node: '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"ec2:Describe*","Resource":"*"}]}'
Defensive patterns

Strategy: validation

Validate before calling

for role, policy := range additionalPolicies {
	var doc struct{ Statement []json.RawMessage `json:"Statement"` }
	if err := json.Unmarshal([]byte(policy), &doc); err != nil {
		return fmt.Errorf("additionalPolicies[%s] invalid JSON: %w", role, err)
	}
	if len(doc.Statement) == 0 {
		return fmt.Errorf("additionalPolicies[%s] has empty Statement array", role)
	}
}

Try / catch

if err := kopsUpdate(); err != nil {
	if strings.Contains(err.Error(), "additionalPolicy") && strings.Contains(err.Error(), "is invalid") {
		// extract roleKey and policy text from the message, validate JSON, fix, retry
	}
	return err
}

Prevention

When it happens

Trigger: Setting spec.additionalPolicies.node (or control-plane/bastion) in the cluster spec to a string that fails iam.ParseStatements — invalid JSON, statement objects instead of arrays, wrong field types, or unrendered template placeholders.

Common situations: Editing cluster.yaml to grant extra permissions and making a JSON syntax mistake; using single quotes or comments inside the policy; multi-line YAML folding producing malformed JSON.

Related errors


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