caddyserver/caddy · error

setting environment variables: %v

Error message

setting environment variables: %v

What it means

Thrown by loadEnvFromFile when os.Setenv fails while injecting a parsed env-file variable into the process environment. Existing environment variables are never overwritten (LookupEnv guard), so this fires only for NEW keys. On Unix, os.Setenv returns EINVAL almost exclusively when the key contains a '=' character or a NUL byte, or when the value contains a NUL byte.

Source

Thrown at cmd/main.go:369

func loadEnvFromFile(envFile string) error {
	file, err := os.Open(envFile)
	if err != nil {
		return fmt.Errorf("reading environment file: %v", err)
	}
	defer file.Close()

	envMap, err := parseEnvFile(file)
	if err != nil {
		return fmt.Errorf("parsing environment file: %v", err)
	}

	for k, v := range envMap {
		// do not overwrite existing environment variables
		_, exists := os.LookupEnv(k)
		if !exists {
			if err := os.Setenv(k, v); err != nil {
				return fmt.Errorf("setting environment variables: %v", err)
			}
		}
	}

	// Update the storage paths to ensure they have the proper
	// value after loading a specified env file.
	caddy.ConfigAutosavePath = filepath.Join(caddy.AppConfigDir(), "autosave.json")
	caddy.DefaultStorage = &certmagic.FileStorage{Path: caddy.AppDataDir()}

	return nil
}

// parseEnvFile parses an env file from KEY=VALUE format.
// It's pretty naive. Limited value quotation is supported,
// but variable and command expansions are not supported.
func parseEnvFile(envInput io.Reader) (map[string]string, error) {
	envMap := make(map[string]string)

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Sanitize the env file: ensure it is plain UTF-8 text with no control/NUL characters (`LC_ALL=C grep -P '[\x00]' env` should print nothing)
  2. Verify no key can contain '=' — keys are everything before the FIRST '=', so 'A=B=C' sets key 'A' correctly; check for unusual quoting instead
  3. Set the same variable in the real environment before starting Caddy: since existing vars are skipped, exporting it externally bypasses Setenv entirely
  4. As a last resort, drop the variable from the env file and pass it via systemd `Environment=` or container env

Example fix

# before: value copied with a control character
TOKEN=abc\x00def

# after
TOKEN=abcdef
Defensive patterns

Strategy: validation

Validate before calling

# reject control characters before handing the file to Caddy
if LC_ALL=C grep -qP '[\x00-\x08\x0b-\x1f]' env; then echo 'env file contains control characters'; exit 1; fi

Prevention

When it happens

Trigger: An env-file line whose key passes the earlier checks yet embeds a character the OS rejects — in practice a value with an embedded NUL (e.g. copied binary/Unicode content), or a key constructed oddly such as 'A=B=C' where parsing quirks yield an invalid key; or running with an environment that forbids mutation.

Common situations: Env files produced by tooling that emits literal escape sequences (\0), values pasted from terminals carrying control characters, or a quoted-value spanning lines (the parser joins lines) that smuggles a stray character into the value.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/a10fdd91feaf57b9. Report an issue: GitHub.