Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Infrastructure as Code By James Joyner IV · · 9 min read

CUE Error: 'conflicting values "prod" and "dev"' — Cause, Fix, and Troubleshooting Guide

Quick answer

Fix CUE 'conflicting values "prod" and "dev"' unification errors — two files or constraints bind the same field to incompatible concrete values.

  • #iac
  • #infrastructure-as-code
  • #cue
  • #troubleshooting
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

CUE has no assignment — it has unification. When the same field is given a value in two places, CUE unifies them: if they are compatible it keeps the most specific, but if they are two different concrete values, unification fails because there is no single value that satisfies both. That is this error:

environment: conflicting values "prod" and "dev":
    ./base.cue:4:18
    ./overlay.cue:2:18

CUE is telling you that environment is constrained to be "prod" by one file and "dev" by another, and both cannot be true at once. The two file:line references are the exact source of each value. This is not a merge that “last write wins” — CUE deliberately refuses, because silently picking one would hide a contradiction. It surfaces during cue vet, cue eval, or cue export.

Symptoms

  • cue vet / cue eval / cue export fails with conflicting values "x" and "y".
  • Two source locations are printed, one per conflicting definition.
  • It appears after adding a second file, a package import, or a -t/tag injection.
  • The same field is set to a concrete value in a base and re-set in an overlay.
  • Numeric or struct variants: conflicting values 3 and 5, or field-level struct clashes.

Common Root Causes

1. The same field set to two concrete values across files

Because files in a package unify, a base and an overlay both fixing the field collide.

// base.cue
environment: "prod"
// overlay.cue  (same package)
environment: "dev"    // conflicts with base.cue

2. Trying to “override” a concrete value

Newcomers expect the overlay to win. In CUE, once a field is concrete you can only narrow it (to the same value), not change it.

replicas: 3
replicas: 5    // conflict, not an override

3. A constraint plus an out-of-range value

A disjunction or bound in one place and a value outside it in another.

environment: "dev" | "staging" | "prod"
environment: "qa"   // conflicting values — "qa" not in the disjunction

4. Struct fields unified from two imported packages

Importing two packages that both define the same path with different concrete values.

import (
  a "example.com/config/a"
  b "example.com/config/b"
)
out: a.settings & b.settings   // clashing concrete fields

5. Tag injection colliding with a hardcoded value

cue export -t env=dev injects into a field already pinned to "prod".

environment: string @tag(env)
environment: "prod"    // -t env=dev then conflicts

How to Diagnose

Run vet to get both source locations

cue vet ./...

The two file:line:col pairs under the message are the exact conflicting definitions — open both.

Evaluate a single field to see how it resolves

cue eval -e environment ./...

This isolates the field and shows the conflict without the surrounding noise.

List which files contribute to the package

cue eval --all-errors ./... 2>&1 | head -40

--all-errors (-E) reports every conflict, not just the first, so you fix them in one pass.

Check for tag-driven conflicts

grep -rn '@tag(' .
cue export -t env=dev ./...   # reproduce the injected value

Fixes

Make one side a constraint, not a concrete value

Turn the base into an open constraint (a type or disjunction) and let the overlay supply the concrete value:

// base.cue — constraint only
environment: "dev" | "staging" | "prod"
// overlay.cue — chooses one allowed value
environment: "dev"

Now unification succeeds because "dev" narrows the disjunction.

Use a default so overlays can override

The * marks a default that a concrete value replaces cleanly:

environment: *"dev" | "staging" | "prod"   // default dev, override allowed

cue export yields dev unless another file narrows it to staging/prod.

Separate environments into distinct packages or files

Do not unify prod and dev in one package. Put them in sibling directories and build each on its own:

cue export ./environments/prod
cue export ./environments/dev

Fix an out-of-range value

Either widen the disjunction to include the new value or correct the value:

environment: "dev" | "staging" | "prod" | "qa"   // add qa if legitimate

Reconcile imported struct clashes

Pick one source of truth for the shared field, or unify only the non-conflicting subsets rather than whole structs.

What to Watch Out For

  • Model base configs as constraints (types, bounds, disjunctions) and let overlays supply concrete values — that is the CUE-idiomatic layering.
  • Use *value defaults for anything you expect an overlay or -t tag to override.
  • Keep distinct environments in distinct packages; unifying them in one package guarantees conflicts.
  • Run cue vet ./... in CI so a contradiction fails the pipeline, not the deploy.
  • Remember CUE is order-independent: there is no “last write wins”, so never rely on file ordering to resolve values.
Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.