dagger/dagger · error

key %q is missing an environment name

Error message

key %q is missing an environment name

What it means

userOverlayKeyParts parses user-level config keys and supports an optional "env.<name>." prefix identifying an environment. When the key starts with "env" but has no environment name following it (e.g. "env.modules.foo.settings.x"), this error is thrown because the parser cannot tell which environment the key belongs to.

Source

Thrown at core/workspace/userconfig.go:237

	if !ok {
		return "", false
	}
	gitDir = strings.TrimSpace(gitDir)
	return gitDir, gitDir != ""
}

// userOverlayKeyParts validates that key addresses user-overridable config and
// returns its parsed path segments. Only module settings may be stored in a
// user-level overlay, always applied or scoped to an environment.
func userOverlayKeyParts(key string) ([]string, error) {
	parts, err := splitConfigPath(key)
	if err != nil {
		return nil, err
	}
	rest := parts
	if len(rest) > 0 && rest[0] == "env" {
		if len(rest) < 2 {
			return nil, fmt.Errorf("key %q is missing an environment name", key)
		}
		rest = rest[2:]
	}
	if len(rest) < 4 || rest[0] != "modules" || rest[2] != "settings" {
		return nil, fmt.Errorf("key %q cannot be stored in user-level config; only modules.<name>.settings.* and env.<name>.modules.<name>.settings.* are supported", key)
	}
	return parts, nil
}

// WriteUserConfigValue sets a config value under [workspaces.<workspaceKey>]
// in user-level config bytes, preserving unrelated sections (e.g. [llm]) and
// other workspace entries. The workspace key is canonicalized; when an entry
// for an equivalent remote spelling already exists, it is updated in place
// rather than duplicated. A non-nil values slice stores a string array
// verbatim; otherwise rawValue is typed like repository config writes.
func WriteUserConfigValue(existing []byte, workspaceKey, key, rawValue string, values []string) ([]byte, error) {
	parts, err := userOverlayKeyParts(key)
	if err != nil {

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Add the environment name after "env": use "env.<name>.modules.<mod>.settings.<key>"
  2. If you do not mean an environment, drop the "env" segment and use "modules.<mod>.settings.<key>"
  3. Split the key on "." and verify segment 2 (index 1) is the environment name, not "modules"

Example fix

// before
WriteUserConfigValue(data, "env.modules.foo.settings.timeout", "30")
// after
WriteUserConfigValue(data, "env.ci.modules.foo.settings.timeout", "30")
Defensive patterns

Strategy: validation

Validate before calling

segs := strings.Split(key, ".")
if segs[0] == "env" && len(segs) < 5 {
	return fmt.Errorf("env-scoped keys need: env.<name>.modules.<mod>.settings.<key>")
}

Type guard

func isWellFormedEnvKey(key string) bool {
	s := strings.Split(key, ".")
	return len(s) < 2 || s[0] != "env" || (len(s) >= 5 && s[1] != "" && s[1] != "modules")
}

Try / catch

_, err := workspace.WriteUserConfigValue(data, key, wsKey, val)
if err != nil && strings.Contains(err.Error(), "missing an environment name") {
	return fmt.Errorf("key %q must include the environment name after 'env'", key)
}

Prevention

When it happens

Trigger: Calling WriteUserConfigValue or DeleteUserConfigValue with a key whose first segment is "env" followed by fewer than 2 remaining segments — e.g. "env", "env.x", or "env.modules.foo.settings.x" (env immediately followed by modules).

Common situations: Typing a config key without the environment name ("dagger config set env.modules.x..."); scripting that drops a segment when building keys programmatically; documentation examples copied incompletely.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/0a082dc99e99e1b8. Report an issue: GitHub.