Skip to main content

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".

StageCategoryMessage
evaluationeval_conflict_errorcomplete 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.