{"record":{"id":"3aa41223691a4777","repo":"kubernetes/kops","slug":"additionalpolicy-q-is-invalid-v","errorCode":null,"errorMessage":"additionalPolicy %q is invalid: %v","messagePattern":"additionalPolicy %q is invalid: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/awsmodel/iam.go","lineNumber":370,"sourceCode":"\t\t\t\t\tif key == \"master\" {\n\t\t\t\t\t\tkey = \"control-plane\"\n\t\t\t\t\t}\n\t\t\t\t\tadditionalPolicy = b.Cluster.Spec.AdditionalPolicies[key]\n\t\t\t\t}\n\n\t\t\t\tadditionalPolicyName := \"additional.\" + iamName\n\n\t\t\t\tt := &awstasks.IAMRolePolicy{\n\t\t\t\t\tName:      new(additionalPolicyName),\n\t\t\t\t\tLifecycle: b.Lifecycle,\n\n\t\t\t\t\tRole: iamRole,\n\t\t\t\t}\n\n\t\t\t\tif additionalPolicy != \"\" {\n\t\t\t\t\tp, err := b.buildPolicy(additionalPolicy)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"additionalPolicy %q is invalid: %v\", roleKey, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tpolicy, err := p.AsJSON()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error building IAM policy: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tt.PolicyDocument = fi.NewStringResource(policy)\n\t\t\t\t} else {\n\t\t\t\t\tt.PolicyDocument = fi.NewStringResource(\"\")\n\t\t\t\t}\n\n\t\t\t\tc.AddTask(t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/awsmodel/iam.go#L352-L388","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nspec:\n  additionalPolicies:\n    node: '{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"ec2:Describe*\",\"Resource\":\"*\"}}'\n// after\nspec:\n  additionalPolicies:\n    node: '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"ec2:Describe*\",\"Resource\":\"*\"}]}'","handlingStrategy":"validation","validationCode":"for role, policy := range additionalPolicies {\n\tvar doc struct{ Statement []json.RawMessage `json:\"Statement\"` }\n\tif err := json.Unmarshal([]byte(policy), &doc); err != nil {\n\t\treturn fmt.Errorf(\"additionalPolicies[%s] invalid JSON: %w\", role, err)\n\t}\n\tif len(doc.Statement) == 0 {\n\t\treturn fmt.Errorf(\"additionalPolicies[%s] has empty Statement array\", role)\n\t}\n}","typeGuard":null,"tryCatchPattern":"if err := kopsUpdate(); err != nil {\n\tif strings.Contains(err.Error(), \"additionalPolicy\") && strings.Contains(err.Error(), \"is invalid\") {\n\t\t// extract roleKey and policy text from the message, validate JSON, fix, retry\n\t}\n\treturn err\n}","preventionTips":["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."],"tags":["aws","iam","policy-validation","json","additionalpolicies"],"backgroundTag":"invalid-iam-policy-json","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}