Repository: spack/spack

Issue:
Concretization errors if a preference doesn't match the type of the variant for a package
### Steps to reproduce

Create an environment like:
```yaml
spack:
  specs:
  - llvm
  - openmpi
  view: true
  concretizer:
    unify: true
  packages:
    all:
      variants: [+openmp]
```
and try to concretize it:
```console
$ spack concretize
==> Error: invalid values for variant "openmp" in package "llvm": ['True']
```
This shouldn't happen when the variant is under the `all:` section.

### Error message

```console
$ spack -d concretize -f
==> [2023-11-17-14:13:54.062723] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/config.yaml
==> [2023-11-17-14:13:54.080177] Reading config from file /home/culpo/.spack/config.yaml
==> [2023-11-17-14:13:54.080805] Reading config from file /tmp/spack-3jx3axqz/spack.yaml
==> [2023-11-17-14:13:54.084330] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/config.yaml
==> [2023-11-17-14:13:54.101653] Reading config from file /home/culpo/.spack/config.yaml
==> [2023-11-17-14:13:54.102171] Using environment '/tmp/spack-3jx3axqz'
==> [2023-11-17-14:13:54.107170] Imported concretize from built-in commands
==> [2023-11-17-14:13:54.107711] Imported concretize from built-in commands
==> [2023-11-17-14:13:54.123985] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/concretizer.yaml
==> [2023-11-17-14:13:54.133070] DATABASE LOCK TIMEOUT: 60s
==> [2023-11-17-14:13:54.133142] PACKAGE LOCK TIMEOUT: No timeout
==> [2023-11-17-14:13:54.133328] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/bootstrap.yaml
==> [2023-11-17-14:13:54.139698] Reading config from file /tmp/spack-3jx3axqz/spack.yaml
==> [2023-11-17-14:13:54.143285] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/config.yaml
==> [2023-11-17-14:13:54.161208] Reading config from file /home/culpo/.spack/config.yaml
==> [2023-11-17-14:13:54.161713] Deactivated environment '/tmp/spack-3jx3axqz'
==> [2023-11-17-14:13:54.163441] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/repos.yaml
==> [2023-11-17-14:13:54.166053] [BOOTSTRAP CONFIG SCOPE] name=_builtin
==> [2023-11-17-14:13:54.166354] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/bootstrap.yaml
==> [2023-11-17-14:13:54.172742] [BOOTSTRAP CONFIG SCOPE] name=defaults, path=/home/culpo/PycharmProjects/spack/etc/spack/defaults
==> [2023-11-17-14:13:54.172869] [BOOTSTRAP CONFIG SCOPE] name=defaults/linux, path=/home/culpo/PycharmProjects/spack/etc/spack/defaults/linux
==> [2023-11-17-14:13:54.172919] [BOOTSTRAP CONFIG SCOPE] name=bootstrap, path=/home/culpo/.spack/bootstrap/config
==> [2023-11-17-14:13:54.172959] [BOOTSTRAP CONFIG SCOPE] name=bootstrap/linux, path=/home/culpo/.spack/bootstrap/config/linux
==> [2023-11-17-14:13:54.174446] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/config.yaml
==> [2023-11-17-14:13:54.193603] Reading config from file /home/culpo/.spack/bootstrap/config/linux/config.yaml
==> [2023-11-17-14:13:54.203517] DATABASE LOCK TIMEOUT: 60s
==> [2023-11-17-14:13:54.203578] PACKAGE LOCK TIMEOUT: No timeout
==> [2023-11-17-14:13:54.203774] Reading config from file /home/culpo/.spack/bootstrap/config/linux/compilers.yaml
==> [2023-11-17-14:13:54.227386] [BOOTSTRAP ROOT SPEC] patchelf@0.13.1: %gcc target=x86_64
==> [2023-11-17-14:13:54.227738] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/bootstrap.yaml
==> [2023-11-17-14:13:54.237674] [BOOTSTRAP EXECUTABLES patchelf] Try installed specs with query 'patchelf@0.13.1: %gcc target=x86_64'
==> [2023-11-17-14:13:54.243963] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/modules.yaml
==> [2023-11-17-14:13:54.254745] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/linux/modules.yaml
==> [2023-11-17-14:13:54.280810] Adding env modifications for patchelf
==> [2023-11-17-14:13:54.327654] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/packages.yaml
==> [2023-11-17-14:13:54.356636] Reading config from file /home/culpo/.spack/bootstrap/config/packages.yaml
==> [2023-11-17-14:13:54.365403] [BOOTSTRAP ROOT SPEC] gnupg@2.3: %gcc target=x86_64
==> [2023-11-17-14:13:54.366719] [BOOTSTRAP ROOT SPEC] clingo-bootstrap@spack+python %gcc target=x86_64
==> [2023-11-17-14:13:54.366759] [BOOTSTRAP MODULE clingo] Try importing from Python
==> [2023-11-17-14:13:54.482067] [BOOTSTRAP MODULE clingo] The installed spec "clingo-bootstrap@spack+python %gcc target=x86_64 ^python@3.11/55qeu52pkt5shpwd7ulugv7wzt5j7vqd" provides the "clingo" Python module
==> [2023-11-17-14:13:54.483052] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/config.yaml
==> [2023-11-17-14:13:54.501627] Reading config from file /home/culpo/.spack/config.yaml
==> [2023-11-17-14:13:54.503693] Reading config from file /tmp/spack-3jx3axqz/spack.yaml
==> [2023-11-17-14:13:54.508724] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/config.yaml
==> [2023-11-17-14:13:54.528214] Reading config from file /home/culpo/.spack/config.yaml
==> [2023-11-17-14:13:54.528832] Using environment '/tmp/spack-3jx3axqz'
==> [2023-11-17-14:13:54.528945] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/concretizer.yaml
==> [2023-11-17-14:13:54.534984] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/repos.yaml
==> [2023-11-17-14:13:54.601761] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/packages.yaml
==> [2023-11-17-14:13:54.725592] Reading config from file /home/culpo/PycharmProjects/spack/etc/spack/defaults/mirrors.yaml
==> [2023-11-17-14:13:54.727844] Reading config from file /home/culpo/.spack/mirrors.yaml
==> [2023-11-17-14:13:54.729079] Checking existence of file:///mirror/build_cache/index.json
==> [2023-11-17-14:13:54.743097] Failure reading URL: <urlopen error [Errno 2] No such file or directory: '/mirror/build_cache/index.json'>
==> [2023-11-17-14:13:56.485923] Reading config from file /home/culpo/.spack/linux/compilers.yaml
==> [2023-11-17-14:13:56.501007] [REUSE] Issues when trying to reuse libelf@0.8.13%gcc@10.2.1 build_system=generic arch=test-debian6-core2/i5m3nzm: Unknown namespace: builtin.mock
==> [2023-11-17-14:13:59.722066] InvalidVariantValueError: invalid values for variant "openmp" in package "llvm": ['True']

==> [2023-11-17-14:13:59.722274] Error: invalid values for variant "openmp" in package "llvm": ['True']

Traceback (most recent call last):
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/main.py", line 1064, in main
    return _main(argv)
           ^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/main.py", line 1019, in _main
    return finish_parse_and_run(parser, cmd_name, args.command, env_format_error)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/main.py", line 1047, in finish_parse_and_run
    return _invoke_command(command, parser, args, unknown)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/main.py", line 648, in _invoke_command
    return_val = command(parser, args)
                 ^^^^^^^^^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/cmd/concretize.py", line 44, in concretize
    concretized_specs = env.concretize(force=args.force, tests=tests)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/environment/environment.py", line 1368, in concretize
    return self._concretize_together(tests=tests)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/environment/environment.py", line 1487, in _concretize_together
    concrete_specs: List[spack.spec.Spec] = spack.concretize.concretize_specs_together(
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/concretize.py", line 741, in concretize_specs_together
    return _concretize_specs_together_new(*abstract_specs, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/concretize.py", line 749, in _concretize_specs_together_new
    result = solver.solve(
             ^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/solver/asp.py", line 3219, in solve
    result, _, _ = self.driver.solve(
                   ^^^^^^^^^^^^^^^^^^
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/solver/asp.py", line 920, in solve
    setup.setup(self, specs, reuse=reuse, allow_deprecated=allow_deprecated)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/solver/asp.py", line 2657, in setup
    self.preferred_variants(pkg)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/solver/asp.py", line 1842, in preferred_variants
    spec.update_variant_validate(variant_name, values)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/spec.py", line 3519, in update_variant_validate
    pkg_variant.validate_or_raise(self.variants[variant_name], pkg_cls)
  File "/home/culpo/PycharmProjects/spack/lib/spack/spack/variant.py", line 126, in validate_or_raise
    raise InvalidVariantValueError(self, not_allowed_values, pkg_cls)
spack.variant.InvalidVariantValueError: invalid values for variant "openmp" in package "llvm": ['True']
```

### Information on your system

@finkandreas 

* **Spack:** 0.22.0.dev0 (54ab0872f24819c1c2f220f99a05990d02a5d8da)
* **Python:** 3.11.5
* **Platform:** linux-ubuntu20.04-icelake
* **Concretizer:** clingo


### General information

- [X] I have run `spack debug report` and reported the version of Spack/Python/Platform
- [X] I have searched the issues of this repo and believe this is not a duplicate
- [X] I have run the failing commands in debug mode and reported the output


Discussion:

Resolving patch:
diff --git a/lib/spack/spack/audit.py b/lib/spack/spack/audit.py
--- a/lib/spack/spack/audit.py
+++ b/lib/spack/spack/audit.py
@@ -286,6 +286,54 @@ def make_error(attribute_name, config_data, summary):
     return errors
 
 
+@config_packages
+def _avoid_mismatched_variants(error_cls):
+    """Warns if variant preferences have mismatched types or names."""
+    errors = []
+    packages_yaml = spack.config.CONFIG.get_config("packages")
+
+    def make_error(config_data, summary):
+        s = io.StringIO()
+        s.write("Occurring in the following file:\n")
+        syaml.dump_config(config_data, stream=s, blame=True)
+        return error_cls(summary=summary, details=[s.getvalue()])
+
+    for pkg_name in packages_yaml:
+        # 'all:' must be more forgiving, since it is setting defaults for everything
+        if pkg_name == "all" or "variants" not in packages_yaml[pkg_name]:
+            continue
+
+        preferences = packages_yaml[pkg_name]["variants"]
+        if not isinstance(preferences, list):
+            preferences = [preferences]
+
+        for variants in preferences:
+            current_spec = spack.spec.Spec(variants)
+            pkg_cls = spack.repo.PATH.get_pkg_class(pkg_name)
+            for variant in current_spec.variants.values():
+                # Variant does not exist at all
+                if variant.name not in pkg_cls.variants:
+                    summary = (
+                        f"Setting a preference for the '{pkg_name}' package to the "
+                        f"non-existing variant '{variant.name}'"
+                    )
+                    errors.append(make_error(preferences, summary))
+                    continue
+
+                # Variant cannot accept this value
+                s = spack.spec.Spec(pkg_name)
+                try:
+                    s.update_variant_validate(variant.name, variant.value)
+                except Exception:
+                    summary = (
+                        f"Setting the variant '{variant.name}' of the '{pkg_name}' package "
+                        f"to the invalid value '{str(variant)}'"
+                    )
+                    errors.append(make_error(preferences, summary))
+
+    return errors
+
+
 #: Sanity checks on package directives
 package_directives = AuditClass(
     group="packages",
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -1839,7 +1839,13 @@ def preferred_variants(self, pkg_name):
 
             # perform validation of the variant and values
             spec = spack.spec.Spec(pkg_name)
-            spec.update_variant_validate(variant_name, values)
+            try:
+                spec.update_variant_validate(variant_name, values)
+            except (spack.variant.InvalidVariantValueError, KeyError, ValueError) as e:
+                tty.debug(
+                    f"[SETUP]: rejected {str(variant)} as a preference for {pkg_name}: {str(e)}"
+                )
+                continue
 
             for value in values:
                 self.variant_values_from_specs.add((pkg_name, variant.name, value))


Test patch:
diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py
--- a/lib/spack/spack/test/concretize_preferences.py
+++ b/lib/spack/spack/test/concretize_preferences.py
@@ -504,3 +504,13 @@ def test_sticky_variant_accounts_for_packages_yaml(self):
         with spack.config.override("packages:sticky-variant", {"variants": "+allow-gcc"}):
             s = Spec("sticky-variant %gcc").concretized()
             assert s.satisfies("%gcc") and s.satisfies("+allow-gcc")
+
+    @pytest.mark.regression("41134")
+    @pytest.mark.only_clingo("Not backporting the fix to the old concretizer")
+    def test_default_preference_variant_different_type_does_not_error(self):
+        """Tests that a different type for an existing variant in the 'all:' section of
+        packages.yaml doesn't fail with an error.
+        """
+        with spack.config.override("packages:all", {"variants": "+foo"}):
+            s = Spec("a").concretized()
+            assert s.satisfies("foo=bar")