docker/cli · error

unexpected environment variable

Error message

unexpected environment variable '%s'

What it means

Raised by buildEnvironment when an entry from os.Environ() cannot be split into KEY=VALUE, i.e. it contains no '=' or has an empty key. The environment entries feed Compose variable interpolation, so a malformed entry would break interpolation silently.

Solutions

  1. Identify the malformed environment string from the error's %s and remove or fix it.
  2. Ensure any environ slice passed to the loader consists of KEY=VALUE entries with a non-empty KEY.
  3. Sanitize/normalize environment entries before invoking the stack deploy path.
  4. On Windows, confirm the malformed entry isn't an MS-DOS '=X' style var; those are filtered, but custom formats may slip through.

Example fix

// before
environ := []string{"FOO", "BAR=baz"}  // "FOO" has no '='
// after
environ := []string{"FOO=", "BAR=baz"}  // well-formed KEY=VALUE
Defensive patterns

Strategy: validation

Validate before calling

// Sanitize an environ slice before passing to the loader
func sanitizeEnviron(env []string) ([]string, error) {
    out := make([]string, 0, len(env))
    for _, s := range env {
        k, v, ok := strings.Cut(s, "=")
        if !ok || k == "" {
            return nil, fmt.Errorf("malformed environment entry %q", s)
        }
        out = append(out, k+"="+v)
    }
    return out, nil
}

Type guard

type EnvEntry struct{ Key, Value string }

func parseEnvEntry(s string) (EnvEntry, error) {
    k, v, ok := strings.Cut(s, "=")
    if !ok || k == "" {
        return EnvEntry{}, fmt.Errorf("invalid env %q", s)
    }
    return EnvEntry{Key: k, Value: v}, nil
}

Prevention

When it happens

Trigger: An environment variable string passed via os.Environ() (or a test fixture) that has no '=' separator or an empty key. strings.Cut at loader.go:134 returns ok=false for a string with no '=', or k=="" when the part before '=' is empty.

Common situations: Extremely rare in production shells (the OS normally enforces KEY=VALUE); seen in tests with malformed fixtures, on platforms injecting unusual env strings, or when an integration passes a crafted environ slice. Windows '='-prefixed MS-DOS vars are already filtered above this check.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/7ac1bb3bf2d35252. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/stack/loader.go:136

func buildEnvironment(env []string) (map[string]string, error) {
	result := make(map[string]string, len(env))
	for _, s := range env {
		if runtime.GOOS == "windows" && len(s) > 0 {
			// cmd.exe can have special environment variables which names start with "=".
			// They are only there for MS-DOS compatibility and we should ignore them.
			// See TestBuildEnvironment for examples.
			//
			// https://ss64.com/nt/syntax-variables.html
			// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
			// https://github.com/docker/cli/issues/4078
			if s[0] == '=' {
				continue
			}
		}

		k, v, ok := strings.Cut(s, "=")
		if !ok || k == "" {
			return result, fmt.Errorf("unexpected environment variable '%s'", s)
		}
		// value may be set, but empty if "s" is like "K=", not "K".
		result[k] = v
	}
	return result, nil
}

func loadConfigFiles(filenames []string, stdin io.Reader) ([]composetypes.ConfigFile, error) {
	configFiles := make([]composetypes.ConfigFile, 0, len(filenames))

	for _, filename := range filenames {
		configFile, err := loadConfigFile(filename, stdin)
		if err != nil {
			return configFiles, err
		}
		configFiles = append(configFiles, *configFile)
	}

View on GitHub (pinned to 4f84911bfe)