nats-io/nats-server · error

variable reference for '%s' on line %d can not be found

Error message

variable reference for '%s' on line %d can not be found

What it means

A variable reference item was syntactically valid but lookupVariable could not find a value in any context map, in the config, or in the process environment (os.LookupEnv). The reference resolves to nothing, so parsing aborts with the reference name and line number.

Source

Thrown at conf/parse.go:390

			return fmt.Errorf(
				"expected Zulu formatted DateTime, but got '%s'", it.val)
		}
		setValue(it, dt)
	case itemArrayStart:
		var array = make([]any, 0)
		p.pushContext(array)
	case itemArrayEnd:
		array := p.ctx
		p.popContext()
		setValue(it, array)
	case itemVariable:
		value, found, err := p.lookupVariable(it.val)
		if err != nil {
			return fmt.Errorf("variable reference for '%s' on line %d could not be parsed: %s",
				it.val, it.line, err)
		}
		if !found {
			return fmt.Errorf("variable reference for '%s' on line %d can not be found",
				it.val, it.line)
		}

		if p.pedantic {
			switch tk := value.(type) {
			case *token:
				// Mark the looked up variable as used, and make
				// the variable reference become handled as a token.
				tk.usedVariable = true
				p.setValue(&token{it, tk.Value(), false, fp})
			default:
				// Special case to add position context to bcrypt references.
				p.setValue(&token{it, value, false, fp})
			}
		} else {
			p.setValue(value)
		}
	case itemInclude:

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Define the referenced key in the config file or push it into the config context before parsing.
  2. Export the environment variable before running the process (os.LookupEnv is consulted as fallback).
  3. Fix typos in the reference name (error includes the name and line number).
  4. Provide a default value at the call site instead of relying on an unset variable.
  5. In CI/CD, ensure the variable is passed into the job/container environment.

Example fix

// before (VAR unset)
secret = ${API_SECRET}
// after
export API_SECRET=... # or define in config:
API_SECRET = literal-value
secret = ${API_SECRET}
Defensive patterns

Strategy: try-catch

Validate before calling

name := "API_SECRET"
if os.LookupEnv(name) == nil {
	return fmt.Errorf("required variable %s is not set", name)
}

Try / catch

var perr interface{ }
if err := parseConfig(); err != nil {
	if strings.Contains(err.Error(), "can not be found") {
		// resolve the missing variable or abort with a clear setup message
		return fmt.Errorf("config setup incomplete: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: processItem (from parse) hits case itemVariable where lookupVariable returns found=false: the referenced key is absent from all pushed contexts, the included config, and the OS environment.

Common situations: Referencing an env var that was never exported (or only set in a different shell/CI stage), typo in the variable name, dependency on a variable set by a deployment manifest that isn't present locally, or referencing a config key defined after the reference in an include file.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/361a92de9b11150c. Report an issue: GitHub.