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 nilView on GitHub (pinned to 4c8573c808)
Solutions
- Validate the policy text with a JSON parser (`jq`) and fix the syntax reported in the wrapped error.
- Ensure each statement object is inside a Statement array with valid Effect/Action/Resource types.
- 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
- Use YAML block scalars (|) with valid JSON, and validate with jq before applying.
- Keep additionalPolicies minimal and version-controlled so regressions are reviewable.
- Run `kops replace -f cluster.yaml` against a scratch cluster in CI to catch policy syntax errors early.
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
- error inline policy: %w
- error parsing expected RolePolicyDocument for IAMRole %q: %v
- error parsing actual RolePolicyDocument for IAMRole %q: %v
- IP version is incorrect
- provider ID cannot be empty
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/3aa41223691a4777.
Report an issue: GitHub.