{"record":{"id":"3008e1c6cea996a8","repo":"hashicorp/nomad","slug":"invalid-operator-capability-s","errorCode":null,"errorMessage":"Invalid operator capability '%s'","messagePattern":"Invalid operator capability '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"acl/policy.go","lineNumber":692,"sourceCode":"\t}\n\n\tp.ExtraKeysHCL = nil\n\n\tif p.Agent != nil && !isPolicyValid(p.Agent.Policy) {\n\t\treturn nil, fmt.Errorf(\"Invalid agent policy: %#v\", p.Agent)\n\t}\n\n\tif p.Node != nil && !isPolicyValid(p.Node.Policy) {\n\t\treturn nil, fmt.Errorf(\"Invalid node policy: %#v\", p.Node)\n\t}\n\n\tif p.Operator != nil {\n\t\tif p.Operator.Policy != \"\" && !isPolicyValid(p.Operator.Policy) {\n\t\t\treturn nil, fmt.Errorf(\"Invalid operator policy: %#v\", p.Operator)\n\t\t}\n\t\tfor _, cap := range p.Operator.Capabilities {\n\t\t\tif !isOperatorCapabilityValid(cap) {\n\t\t\t\treturn nil, fmt.Errorf(\"Invalid operator capability '%s'\", cap)\n\t\t\t}\n\t\t}\n\n\t\t// Expand the short hand policy to the capabilities and\n\t\t// add to any existing capabilities\n\t\tif p.Operator.Policy != \"\" {\n\t\t\textraCap := expandOperatorPolicy(p.Operator.Policy)\n\t\t\tp.Operator.Capabilities = append(p.Operator.Capabilities, extraCap...)\n\t\t}\n\t}\n\n\tif p.Sentinel != nil {\n\t\tif p.Sentinel.Policy != \"\" && !isPolicyValid(p.Sentinel.Policy) {\n\t\t\treturn nil, fmt.Errorf(\"Invalid sentinel policy: %#v\", p.Sentinel)\n\t\t}\n\t\tfor _, cap := range p.Sentinel.Capabilities {\n\t\t\tif !isSentinelCapabilityValid(cap) {\n\t\t\t\treturn nil, fmt.Errorf(\"Invalid sentinel capability '%s'\", cap)","sourceCodeStart":674,"sourceCodeEnd":710,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/acl/policy.go#L674-L710","documentation":"acl.Parse (acl/policy.go:692) checks each entry of the operator block's Capabilities list with isOperatorCapabilityValid, which only accepts deny, snapshot-save, keyring-rotate, keyring-read, keyring-delete, and license-read. Any other capability string fails parsing and rejects the whole policy.","triggerScenarios":"acl.Parse on a policy where operator { capabilities = [...] } contains an unrecognized string such as 'snapshot', 'license-manager', or a namespace capability like 'submit-job'.","commonSituations":"Typos or shortened forms of capability names ('snapshot' vs 'snapshot-save'); version drift — 'license-read' only exists in Nomad Enterprise/newer versions, so policies generated elsewhere may carry unsupported entries; confusing operator capabilities with node-pool or sentinel capabilities.","solutions":["Replace the invalid capability with one of exactly: deny, snapshot-save, keyring-rotate, keyring-read, keyring-delete, license-read.","Alternatively remove capabilities and use shorthand policy = \"read\"|\"write\"|\"deny\".","The '%s' in the error names the exact rejected capability — fix that entry."],"exampleFix":"// before\noperator {\n  capabilities = [\"snapshot\"]\n}\n// after\noperator {\n  capabilities = [\"snapshot-save\"]\n}","handlingStrategy":"validation","validationCode":"var validOperatorCaps = map[string]bool{\"deny\": true, \"snapshot-save\": true, \"keyring-rotate\": true,\n    \"keyring-read\": true, \"keyring-delete\": true, \"license-read\": true}\nif policy.Operator != nil {\n    for _, c := range policy.Operator.Capabilities {\n        if !validOperatorCaps[c] {\n            return fmt.Errorf(\"invalid operator capability %q\", c)\n        }\n    }\n}","typeGuard":"func isOperatorCapabilityValid(cap string) bool {\n    switch cap {\n    case \"deny\", \"snapshot-save\", \"keyring-rotate\", \"keyring-read\", \"keyring-delete\", \"license-read\":\n        return true\n    }\n    return false\n}","tryCatchPattern":"_, err := acl.Parse(rules, acl.PolicyParseStrict)\nif err != nil {\n    if strings.Contains(err.Error(), \"Invalid operator capability\") {\n        // fix the quoted capability name in the operator block\n    }\n    return err\n}","preventionTips":["Use the exact capability literals: deny, snapshot-save, keyring-rotate, keyring-read, keyring-delete, license-read","Remember license-read is Enterprise-only; don't ship it in OSS-only policy sets","Centralize capability constants in tooling instead of hand-typing them"],"tags":["nomad","acl","capability-validation","operator"],"backgroundTag":"acl-policy-validation-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}