Skip to content

ProductEntity and derived params become stale when --product overrides TOML/env via second getopt.Parse() #742

Open

Description

@MatthewJohn

In lib/param_parsing/parameters.go, populateParams calls setupProductParam (~line 189) to set ProductEntity, default MirrorURL, and default CustomBinaryPath based on the resolved params.Product. However, a second getopt.Parse() is called later (~line 241) to enforce "CLI always wins" semantics.

If a user specifies --product on the CLI and a different product value appears in a TOML config file, the sequence is:

  1. First getopt.Parse() – CLI value is applied (e.g. opentofu).
  2. getParamsTOML() – TOML overrides with a different value (e.g. terraform).
  3. GetParamsFromEnvironment() – env-based product may apply.
  4. setupProductParam() – resolves ProductEntity, MirrorURL, CustomBinaryPath from the current (TOML/env) value of params.Product.
  5. Second getopt.Parse() – re-applies the CLI value, so params.Product becomes opentofu again…
  6. …but ProductEntity, MirrorURL, and CustomBinaryPath still reflect terraform from step 4.

This means the product-derived defaults are inconsistent with params.Product after the second parse, which can lead to the wrong binary path and mirror URL being used.

Steps to Reproduce:

  1. Create a ~/.tfswitch.toml containing product = "terraform".
  2. Run tfswitch --product opentofu.
  3. Observe that the effective mirror URL and binary path may still resolve to Terraform's defaults instead of OpenTofu's.

Possible Fix: Call setupProductParam(&params) after the second getopt.Parse(), or guard it so it only resets defaults that haven't been explicitly set.

Context: Identified during review of PR #739 (commit 7ba67d7). Not introduced by that PR — this is a latent issue in the existing parameter-resolution flow.

Activity

  1. self-assigned this
    on Jul 3, 2026
  2. hiSandog commented on Jul 3, 2026

    @hiSandog

    The stale ProductEntity behavior sounds like precedence is being applied in more than one place. A cleaner fix would centralize product resolution after CLI/env/TOML parsing, then derive all product-specific params from that final value once. The regression test should cover TOML default, env override, and --product override together so the second getopt.Parse() path cannot reintroduce stale derived fields.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions