{"record":{"id":"252017942e70585f","repo":"kubernetes/kops","slug":"error-parsing-cloudformation-policy-document-from","errorCode":null,"errorMessage":"error parsing cloudformation policy document from JSON: %v","messagePattern":"error parsing cloudformation policy document from JSON: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/awstasks/iamrolepolicy.go","lineNumber":126,"sourceCode":"\tp := response\n\tactual.Role = &IAMRole{Name: p.RoleName}\n\tif aws.ToString(e.Role.Name) == aws.ToString(p.RoleName) {\n\t\tactual.Role.ID = e.Role.ID\n\t}\n\tif p.PolicyDocument != nil {\n\t\t// The PolicyDocument is URI encoded (?)\n\t\tpolicy := *p.PolicyDocument\n\t\tpolicy, err = url.QueryUnescape(policy)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing PolicyDocument for IAMRolePolicy %q: %v\", aws.ToString(e.Name), err)\n\t\t}\n\n\t\t// Reformat the PolicyDocument by unmarshaling and re-marshaling to JSON.\n\t\t// This will make it possible to compare it when using CloudFormation.\n\t\tvar jsonData interface{}\n\t\terr = json.Unmarshal([]byte(policy), &jsonData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing cloudformation policy document from JSON: %v\", err)\n\t\t}\n\t\tjsonBytes, err := json.MarshalIndent(jsonData, \"\", \"  \")\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error converting cloudformation policy document to JSON: %v\", err)\n\t\t}\n\t\tactual.PolicyDocument = fi.NewStringResource(string(jsonBytes))\n\t}\n\n\tactual.Name = p.PolicyName\n\n\te.ID = actual.ID\n\n\t// Avoid spurious changes\n\tactual.Lifecycle = e.Lifecycle\n\n\treturn &actual, nil\n}\n","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/awstasks/iamrolepolicy.go#L108-L144","documentation":"After URL-decoding, Find unmarshals the policy document as JSON so it can re-marshal it in a canonical, indented form for comparison. If the decoded document is not valid JSON, this error is returned and reconciliation of the policy aborts.","triggerScenarios":"GetRolePolicy returns a decoded PolicyDocument that fails json.Unmarshal — non-JSON content, truncated document, or JSON with unsupported constructs.","commonSituations":"Inline policy manually edited on AWS into invalid JSON; policy created by external tooling (e.g. YAML converted incorrectly); truncated response due to network/proxy issues.","solutions":["Validate the policy with `aws iam get-role-policy` output through a JSON linter","Replace the malformed policy via `aws iam put-role-policy` with a valid JSON document","Re-run `kops update cluster` to overwrite with the kops-managed policy","Check for proxies/middles that could truncate the IAM response"],"exampleFix":"// validate the policy JSON before applying externally\npython3 -m json.tool policy.json  # must succeed\naws iam put-role-policy --role-name nodes --policy-name kops-policy --policy-document file://policy.json","handlingStrategy":"validation","validationCode":"// validate stored policy is valid JSON before kops runs\nout, _ := iamClient.GetRolePolicy(ctx, req)\ndecoded, _ := url.QueryUnescape(*out.PolicyDocument)\nvar v any\nif err := json.Unmarshal([]byte(decoded), &v); err != nil {\n  // fix with aws iam put-role-policy\n}","typeGuard":null,"tryCatchPattern":"if err := kopsUpdate(); err != nil {\n  if strings.Contains(err.Error(), \"parsing cloudformation policy document\") {\n    // overwrite the invalid policy with a valid JSON document, then retry\n  }\n}","preventionTips":["Run policy JSON through a linter before applying anywhere","Never create kops-named inline policies with hand-written JSON","Verify no proxy truncates IAM API responses","Use kops to regenerate the policy after detecting invalid JSON"],"tags":["iam","json","policy-document"],"backgroundTag":"policy-document-parse-failed","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"}