headroomlabs-ai/headroom · error · ValueError

Windows environment mutation is missing a variable name

Error message

Windows environment mutation is missing a variable name

What it means

Raised during uninstall/rollback in _remove_windows_env_scope when a persisted 'windows-env' ManagedMutation record lacks a valid 'name' string in its data dict. The mutation log is the record of what the installer changed (previous env var values) so it can be reverted; a record without a variable name cannot be reverted, so the loop aborts. This is internal-state corruption, almost always caused by an older manifest schema, a hand-edited manifest.json, or a bug that wrote incomplete mutation records.

Source

Thrown at headroom/install/providers.py:132

                target="env",
                kind="windows-env",
                data={
                    "name": name,
                    "scope": scope_name,
                    "previous": None if previous == "__HEADROOM_UNSET__" else previous,
                },
            )
        )
    return mutations


def _remove_windows_env_scope(mutations: list[ManagedMutation]) -> None:
    for mutation in mutations:
        if mutation.kind != "windows-env":
            continue
        name = mutation.data.get("name")
        if not isinstance(name, str):
            raise ValueError("Windows environment mutation is missing a variable name")
        scope_name = mutation.data.get("scope", "User")
        if not isinstance(scope_name, str):
            raise ValueError("Windows environment mutation is missing a valid scope")
        previous = mutation.data.get("previous")
        if previous is None:
            value_literal = "$null"
        else:
            value_literal = _powershell_literal(previous)
        command = [
            "powershell",
            "-NoProfile",
            "-Command",
            f"[Environment]::SetEnvironmentVariable({_powershell_literal(name)},{value_literal},{_powershell_literal(scope_name)})",
        ]
        subprocess.run(command, check=True)


def apply_mutations(manifest: DeploymentManifest) -> list[ManagedMutation]:

View on GitHub (pinned to 322425c43b)

Solutions

  1. Open the profile's manifest.json (path is in the error context / deployment root) and find the windows-env mutation; add the correct "name": "<VAR>" field.
  2. If the variable name is unrecoverable, delete that single mutation entry and revert the remaining ones — then manually run [Environment]::SetEnvironmentVariable('<VAR>',$null,'User') for the known variable.
  3. Regenerate state: fully uninstall via --force/cleanup if available, then reinstall to rebuild a valid manifest.
  4. Report the schema gap if it reproduces on a fresh install — that indicates a writer bug, not corruption.

Example fix

// before (manifest.json, corrupt entry)
{"kind": "windows-env", "data": {"scope": "User", "previous": "x"}}

// after
{"kind": "windows-env", "data": {"name": "HEADROOM_API_KEY", "scope": "User", "previous": "x"}}
Defensive patterns

Strategy: validation

Validate before calling

from headroom.install.providers import _remove_windows_env_scope  # if public elsewhere, prefer that API

for m in manifest.mutations:
    if m.kind == "windows-env" and not isinstance(m.data.get("name"), str):
        raise SystemExit(f"corrupt windows-env mutation (no name): {m.data!r} — fix manifest before uninstall")

Type guard

def is_valid_windows_env_mutation(mutation) -> bool:
    return (
        mutation.kind == "windows-env"
        and isinstance(mutation.data.get("name"), str)
        and isinstance(mutation.data.get("scope", "User"), str)
    )

Try / catch

try:
    uninstall(profile)
except ValueError as e:
    if "missing a variable name" in str(e):
        logger.error("manifest has incomplete windows-env records; edit %s and rerun", manifest_path)
        sys.exit(3)
    raise

Prevention

When it happens

Trigger: Running uninstall/rollback of a headroom deployment whose <deployment-root>/<profile>/manifest.json contains a windows-env mutation with name missing, null, or non-string (e.g. {}). Also when a new field was introduced and old manifests predate it.

Common situations: Upgrading headroom across schema changes; users hand-editing manifests to 'clean up'; partial writes if the process died mid-install; third-party tooling rewriting JSON and dropping empty-looking keys.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/dad2016b7f6451fc. Report an issue: GitHub.