eval_conflict_error: complete rules must not produce multiple outputs
Complete rules are rules that evaluate to a single value, or possibly, don't complete evaluation at all (where their
value is undefined
). An "output" in this context could be likened to a return value, as should be familiar to
most developers. While Rego rules can be incrementally defined in multiple statements, a complete rule can't produce
multiple outputs, or "return values".
Stage | Category | Message |
---|---|---|
evaluation | eval_conflict_error | complete rules must not produce multiple outputs |
Examples
The most trivial example of this would be to simply — and unconditionally — assign two different values to a rule:
package policy
x := 1
x := 2
Naturally, x
can't be both 1
and 2
at the same time! Real-world examples are commonly not this obvious, but most
often involve scenarios where both rules check for conditions that can potentially both be true. Consider the
following example:
package policy
import future.keywords.if
first_name := input.user.first_name
first_name := split(input.user.full_name, " ")[0] if {
input.user.full_name != ""
}
This might seem like a reasonable way to extract the first name from a full name in case the first name isn't already
provided in the input
. And in most cases, it is! A policy like this could work for a long time before failing,
if ever. Even if the first_name
is provided for the user, it's likely going to match the first word of the
full_name
so this rule has a good chance to work for weeks, months, or even years, before multiple outputs are
produced. However, once presented with input
like the following, the rule will fail:
{
"user": {
"first_name": "Johan",
"full_name": "John Doe"
}
}
Even when a condition like this is deemed "impossible" — perhaps because another system's constraints forbid it, it should be considered a best practice to account for this type of scenario in your policies.
How To Fix It
To fix this — simply ensure that the conditions for a rule to be assigned a conflicting value are mutually exclusive.
A common way to do this is to use negation (i.e. not
) in one of the rule bodies:
package policy
import future.keywords.if
first_name := input.user.first_name
first_name := split(input.user.full_name, " ")[0] if {
not input.user.first_name
input.user.full_name != ""
}
Community
For questions, discussions and announcements related to OPA, or Styra products, services and open source projects, please join the Styra Community on Slack.