{"record":{"id":"bb1c4d1362f94b44","repo":"hashicorp/nomad","slug":"invalid-sentinel-capability-s","errorCode":null,"errorMessage":"Invalid sentinel capability '%s'","messagePattern":"Invalid sentinel capability '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"acl/policy.go","lineNumber":710,"sourceCode":"\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)\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.Sentinel.Policy != \"\" {\n\t\t\textraCap := expandSentinelPolicy(p.Sentinel.Policy)\n\t\t\tp.Sentinel.Capabilities = append(p.Sentinel.Capabilities, extraCap...)\n\t\t}\n\t}\n\n\tif p.Quota != nil && !isPolicyValid(p.Quota.Policy) {\n\t\treturn nil, fmt.Errorf(\"Invalid quota policy: %#v\", p.Quota)\n\t}\n\n\tif p.Plugin != nil && !p.Plugin.isValid() {\n\t\treturn nil, fmt.Errorf(\"Invalid plugin policy: %#v\", p.Plugin)\n\t}","sourceCodeStart":692,"sourceCodeEnd":728,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/acl/policy.go#L692-L728","documentation":"acl.Parse (acl/policy.go:710) checks each entry of the sentinel block's Capabilities list with isSentinelCapabilityValid, which only accepts deny, sentinel-read, sentinel-submit, and sentinel-delete. Any other capability string fails parsing and rejects the whole policy.","triggerScenarios":"acl.Parse on a policy where sentinel { capabilities = [...] } contains an unrecognized string such as 'read', 'submit', 'sentinel-write', or a namespace capability name.","commonSituations":"Dropping the 'sentinel-' prefix (writing 'read'/'submit' instead of 'sentinel-read'/'sentinel-submit'); assuming a 'sentinel-write' exists; generating policies from generic ACL templates that don't know the sentinel capability vocabulary.","solutions":["Replace the invalid capability with one of exactly: deny, sentinel-read, sentinel-submit, sentinel-delete.","Alternatively remove capabilities and use shorthand policy = \"read\"|\"write\"|\"deny\" (write expands to sentinel-read + sentinel-submit + sentinel-delete).","The '%s' in the error names the exact rejected capability — fix that entry."],"exampleFix":"// before\nsentinel {\n  capabilities = [\"submit\", \"delete\"]\n}\n// after\nsentinel {\n  capabilities = [\"sentinel-submit\", \"sentinel-delete\"]\n}","handlingStrategy":"validation","validationCode":"var validSentinelCaps = map[string]bool{\"deny\": true, \"sentinel-read\": true,\n    \"sentinel-submit\": true, \"sentinel-delete\": true}\nif policy.Sentinel != nil {\n    for _, c := range policy.Sentinel.Capabilities {\n        if !validSentinelCaps[c] {\n            return fmt.Errorf(\"invalid sentinel capability %q\", c)\n        }\n    }\n}","typeGuard":"func isSentinelCapabilityValid(cap string) bool {\n    switch cap {\n    case \"deny\", \"sentinel-read\", \"sentinel-submit\", \"sentinel-delete\":\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 sentinel capability\") {\n        // prefix bare names with 'sentinel-' or use the policy shorthand\n    }\n    return err\n}","preventionTips":["Always include the 'sentinel-' prefix: sentinel-read, sentinel-submit, sentinel-delete","There is no 'sentinel-write'; use policy = \"write\" or enumerate submit+delete","Copy capability constants from acl.SentinelCapability* rather than typing them"],"tags":["nomad","acl","capability-validation","sentinel","enterprise"],"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"}