Skip to main content

rego_unsafe_var_error: var {name} is unsafe

This is one of the most common errors reported by OPA. When a variable is "unsafe" it simply means that OPA wasn't able to determine where to find it. This is commonly caused by misspelling the name of the variable, or perhaps by referencing a rule or function that dosn't (yet) exist. Note that this check happens at compile time. This means that references like input.username will not be considered unsafe even when there is no username attribute in the input — as the value of input isn't known at compile time.

compilationrego_unsafe_var_errorvar {name} is unsafe (where {name} is the name of the variable)


Can you spot the unsafe variable in the following policy?

package policy

import future.keywords.if

allow if {
input.request.path == "/api"

allow if user_is_admin

user_is_developer if "developer" in input.user.roles

Not that easy! But luckily we won't have to, as the compiler does it for us:

1 error occurred: policy.rego:11: rego_unsafe_var_error: var user_is_admin is unsafe

Of course! We had forgotten to provide an actual user_is_admin rule before we used it, and hence why it's considered unsafe.

Sometimes, the location of the errors isn't as clear-cut, even when reading the errors. Consider the following example. Which variable is unsafe?

package policy

import future.keywords.if

allow if {
first_user := users[0]
title := first_user.title
title_upper := upper(title)

title_upper == "CEO"

You'd be excused to say users, and you'd even be right. But it doesn't stop there:

4 errors occurred:
policy.rego:7: rego_unsafe_var_error: var first_user is unsafe
policy.rego:7: rego_unsafe_var_error: var users is unsafe
policy.rego:8: rego_unsafe_var_error: var title is unsafe
policy.rego:9: rego_unsafe_var_error: var title_upper is unsafe

Since users is unsafe, every variable that depend on users is also considered unsafe. This means that all the variables in our allow rule will be considered unsafe, and we'll have to do some investigative work to figure out what the actual root cause was. Whether this should be needed or not is up for debate, and perhaps we'll be able to skip this in future OPA versions.

How To Fix It

Fixing this is luckily easy. Once you've found the unsafe variable, first of all figure out why it's considered unsafe. In most cases you'll find it was a typo, and those are luckily easy to fix! In some cases it could be that you're referencing a rule or a function from another package, but have forgotten to load that file during compilation.

One thing to keep in mind is that all OPA commands that accept a file may just as well be provided a directory, which will be loaded recursively. This is is often the best way to ensure all the files you may depend on are loaded and available during compilation.

More Information

Remember how we said earlier that the compiler won't consider a reference like input.usrname (note the typo!) unsafe, even though we clearly intended to say input.username? Wouldn't it be great if we had some way to tell the OPA compiler what the input object should look like, and have it include that in this type of check? Luckily, there is! The desired structure (i.e. the schema) of both input and data may be provided to the compiler via OPA's JSON schema capability, thus extending the compiler and the type checker with this information. It'll take some work to set up, but it's well worth it!


For questions, discussions and announcements related to OPA, or Styra products, services and open source projects, please join the Styra Community on Slack.