Repository: ESMValGroup/ESMValCore

Issue:
Proposal to deprecate the `callback` argument from `esmvalcore.preprocessor.load` in v2.8 and remove it in v2.10.
I would like to deprecate the `callback` argument from the [`esmvalcore.preprocessor.load`](https://docs.esmvaltool.org/projects/esmvalcore/en/latest/api/esmvalcore.preprocessor.html#esmvalcore.preprocessor.load) function because it

1) does not seem likely that anyone uses this as it cannot be meaningfully set from the recipe
2) prevents implementation of a simple `Dataset.load` function in #1609. See the [example notebook](https://github.com/ESMValGroup/ESMValCore/blob/split-recipe/notebooks/Dataset.ipynb) for the intended use of `Dataset.load`. This function would do everything related to loading the data: fixes, cmor checks, concatenation, and attaching ancillary variables.

@ESMValGroup/esmvaltool-coreteam Would this change cause problems for your work?

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/ESMValGroup/ESMValCore/pull/2207?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ESMValGroup) Report
> Merging [#2207](https://app.codecov.io/gh/ESMValGroup/ESMValCore/pull/2207?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ESMValGroup) (fded02d) into [main](https://app.codecov.io/gh/ESMValGroup/ESMValCore/commit/a6f257a3f29b77e9449901ecbdb7b89c0177d083?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ESMValGroup) (a6f257a) will **decrease** coverage by `0.01%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main    #2207      +/-   ##
==========================================
- Coverage   93.14%   93.14%   -0.01%     
==========================================
  Files         237      237              
  Lines       12841    12831      -10     
==========================================
- Hits        11961    11951      -10     
  Misses        880      880              
```


| [Files](https://app.codecov.io/gh/ESMValGroup/ESMValCore/pull/2207?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ESMValGroup) | Coverage Δ | |
|---|---|---|
| [esmvalcore/\_recipe/recipe.py](https://app.codecov.io/gh/ESMValGroup/ESMValCore/pull/2207?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ESMValGroup#diff-ZXNtdmFsY29yZS9fcmVjaXBlL3JlY2lwZS5weQ==) | `99.01% <ø> (-0.01%)` | :arrow_down: |
| [esmvalcore/dataset.py](https://app.codecov.io/gh/ESMValGroup/ESMValCore/pull/2207?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ESMValGroup#diff-ZXNtdmFsY29yZS9kYXRhc2V0LnB5) | `100.00% <100.00%> (ø)` | |
| [esmvalcore/preprocessor/\_\_init\_\_.py](https://app.codecov.io/gh/ESMValGroup/ESMValCore/pull/2207?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ESMValGroup#diff-ZXNtdmFsY29yZS9wcmVwcm9jZXNzb3IvX19pbml0X18ucHk=) | `95.22% <100.00%> (-0.02%)` | :arrow_down: |
| [esmvalcore/preprocessor/\_io.py](https://app.codecov.io/gh/ESMValGroup/ESMValCore/pull/2207?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ESMValGroup#diff-ZXNtdmFsY29yZS9wcmVwcm9jZXNzb3IvX2lvLnB5) | `86.80% <100.00%> (-0.31%)` | :arrow_down: |



Patch:
diff --git a/esmvalcore/_recipe/recipe.py b/esmvalcore/_recipe/recipe.py
index ed858e0c3..6f003e17e 100644
--- a/esmvalcore/_recipe/recipe.py
+++ b/esmvalcore/_recipe/recipe.py
@@ -213,9 +213,6 @@ def _get_default_settings(dataset):
 
     settings = {}
 
-    # Configure (deprecated, remove for v2.10.0) load callback
-    settings['load'] = {'callback': 'default'}
-
     if _derive_needed(dataset):
         settings['derive'] = {
             'short_name': facets['short_name'],
diff --git a/esmvalcore/cmor/_fixes/cmip6/iitm_esm.py b/esmvalcore/cmor/_fixes/cmip6/iitm_esm.py
index 6ee5833c2..a6dee710c 100644
--- a/esmvalcore/cmor/_fixes/cmip6/iitm_esm.py
+++ b/esmvalcore/cmor/_fixes/cmip6/iitm_esm.py
@@ -3,7 +3,7 @@ import logging
 
 import numpy as np
 
-from esmvalcore.cmor.check import _get_time_bounds
+from esmvalcore.cmor._fixes.fix import get_time_bounds
 
 from ..common import OceanFixGrid
 from ..fix import Fix
@@ -33,7 +33,7 @@ class AllVars(Fix):
         for cube in cubes:
             freq = self.extra_facets["frequency"]
             time = cube.coord("time", dim_coords=True)
-            bounds = _get_time_bounds(time, freq)
+            bounds = get_time_bounds(time, freq)
             if np.any(bounds != time.bounds):
                 time.bounds = bounds
         logger.warning(
diff --git a/esmvalcore/cmor/_fixes/cmip6/kace_1_0_g.py b/esmvalcore/cmor/_fixes/cmip6/kace_1_0_g.py
index f2a0a1b7a..5e27377b0 100644
--- a/esmvalcore/cmor/_fixes/cmip6/kace_1_0_g.py
+++ b/esmvalcore/cmor/_fixes/cmip6/kace_1_0_g.py
@@ -3,7 +3,7 @@ import logging
 
 import numpy as np
 
-from esmvalcore.cmor.check import _get_time_bounds
+from esmvalcore.cmor._fixes.fix import get_time_bounds
 
 from ..common import ClFixHybridHeightCoord, OceanFixGrid
 from ..fix import Fix
@@ -39,7 +39,7 @@ class AllVars(Fix):
         for cube in cubes:
             freq = self.extra_facets["frequency"]
             time = cube.coord("time", dim_coords=True)
-            bounds = _get_time_bounds(time, freq)
+            bounds = get_time_bounds(time, freq)
             if np.any(bounds != time.bounds):
                 time.bounds = bounds
         logger.warning(
diff --git a/esmvalcore/cmor/_fixes/fix.py b/esmvalcore/cmor/_fixes/fix.py
index 2deeb0d6d..4b5163d4a 100644
--- a/esmvalcore/cmor/_fixes/fix.py
+++ b/esmvalcore/cmor/_fixes/fix.py
@@ -3,17 +3,36 @@ from __future__ import annotations
 
 import importlib
 import inspect
+import logging
 import tempfile
+from collections.abc import Sequence
+from datetime import datetime
 from pathlib import Path
 from typing import TYPE_CHECKING, Any, Optional
 
+import numpy as np
+from cf_units import Unit
+from iris.coords import Coord, CoordExtent
 from iris.cube import Cube, CubeList
-
-from ..table import CMOR_TABLES
+from iris.exceptions import UnitConversionError
+from iris.util import reverse
+
+from esmvalcore.cmor._utils import (
+    _get_alternative_generic_lev_coord,
+    _get_generic_lev_coord_names,
+    _get_new_generic_level_coord,
+    _get_simplified_calendar,
+    _get_single_cube,
+    _is_unstructured_grid,
+)
+from esmvalcore.cmor.table import get_var_info
+from esmvalcore.iris_helpers import date2num
 
 if TYPE_CHECKING:
-    from ...config import Session
-    from ..table import VariableInfo
+    from esmvalcore.cmor.table import CoordinateInfo, VariableInfo
+    from esmvalcore.config import Session
+
+logger = logging.getLogger(__name__)
 
 
 class Fix:
@@ -24,19 +43,23 @@ class Fix:
         vardef: VariableInfo,
         extra_facets: Optional[dict] = None,
         session: Optional[Session] = None,
+        frequency: Optional[str] = None,
     ) -> None:
         """Initialize fix object.
 
         Parameters
         ----------
         vardef:
-            CMOR table entry.
+            CMOR table entry of the variable.
         extra_facets:
             Extra facets are mainly used for data outside of the big projects
             like CMIP, CORDEX, obs4MIPs. For details, see :ref:`extra_facets`.
         session:
             Current session which includes configuration and directory
             information.
+        frequency:
+            Expected frequency of the variable. If not given, use the one from
+            the CMOR table entry of the variable.
 
         """
         self.vardef = vardef
@@ -44,6 +67,9 @@ class Fix:
             extra_facets = {}
         self.extra_facets = extra_facets
         self.session = session
+        if frequency is None and self.vardef is not None:
+            frequency = self.vardef.frequency
+        self.frequency = frequency
 
     def fix_file(
         self,
@@ -76,7 +102,7 @@ class Fix:
         """
         return filepath
 
-    def fix_metadata(self, cubes: CubeList) -> CubeList:
+    def fix_metadata(self, cubes: Sequence[Cube]) -> Sequence[Cube]:
         """Apply fixes to the metadata of the cube.
 
         Changes applied here must not require data loading.
@@ -90,7 +116,7 @@ class Fix:
 
         Returns
         -------
-        iris.cube.CubeList
+        Iterable[iris.cube.Cube]
             Fixed cubes. They can be different instances.
 
         """
@@ -163,6 +189,7 @@ class Fix:
         short_name: str,
         extra_facets: Optional[dict] = None,
         session: Optional[Session] = None,
+        frequency: Optional[str] = None,
     ) -> list:
         """Get the fixes that must be applied for a given dataset.
 
@@ -177,6 +204,8 @@ class Fix:
         before checking because it is not possible to use the character '-' in
         python names.
 
+        In addition, generic fixes for all datasets are added.
+
         Parameters
         ----------
         project:
@@ -193,6 +222,9 @@ class Fix:
         session:
             Current session which includes configuration and directory
             information.
+        frequency:
+            Expected frequency of the variable. If not given, use the one from
+            the CMOR table entry of the variable.
 
         Returns
         -------
@@ -200,8 +232,7 @@ class Fix:
             Fixes to apply for the given data.
 
         """
-        cmor_table = CMOR_TABLES[project]
-        vardef = cmor_table.get_variable(mip, short_name)
+        vardef = get_var_info(project, mip, short_name)
 
         project = project.replace('-', '_').lower()
         dataset = dataset.replace('-', '_').lower()
@@ -238,9 +269,24 @@ class Fix:
             )
             for fix_name in (short_name, mip.lower(), 'allvars'):
                 if fix_name in classes:
-                    fixes.append(classes[fix_name](
-                        vardef, extra_facets=extra_facets, session=session
-                    ))
+                    fixes.append(
+                        classes[fix_name](
+                            vardef,
+                            extra_facets=extra_facets,
+                            session=session,
+                            frequency=frequency,
+                        )
+                    )
+
+        # Always perform generic fixes for all datasets
+        fixes.append(
+            GenericFix(
+                vardef,  # type: ignore
+                extra_facets=extra_facets,
+                session=session,
+                frequency=frequency,
+            )
+        )
 
         return fixes
 
@@ -277,3 +323,661 @@ class Fix:
         else:
             output_dir.mkdir(parents=True, exist_ok=True)
         return output_dir / Path(filepath).name
+
+
+def get_next_month(month: int, year: int) -> tuple[int, int]:
+    """Get next month and year.
+
+    Parameters
+    ----------
+    month:
+        Current month.
+    year:
+        Current year.
+
+    Returns
+    -------
+    tuple[int, int]
+        Next month and next year.
+
+    """
+    if month != 12:
+        return month + 1, year
+    return 1, year + 1
+
+
+def get_time_bounds(time: Coord, freq: str):
+    """Get bounds for time coordinate.
+
+    Parameters
+    ----------
+    time:
+        Time coordinate.
+    freq:
+        Frequency.
+
+    Returns
+    -------
+    np.ndarray
+        Time bounds
+
+    Raises
+    ------
+    NotImplementedError
+        Non-supported frequency is given.
+
+    """
+    bounds = []
+    dates = time.units.num2date(time.points)
+    for step, date in enumerate(dates):
+        month = date.month
+        year = date.year
+        if freq in ['mon', 'mo']:
+            next_month, next_year = get_next_month(month, year)
+            min_bound = date2num(datetime(year, month, 1, 0, 0),
+                                 time.units, time.dtype)
+            max_bound = date2num(datetime(next_year, next_month, 1, 0, 0),
+                                 time.units, time.dtype)
+        elif freq == 'yr':
+            min_bound = date2num(datetime(year, 1, 1, 0, 0),
+                                 time.units, time.dtype)
+            max_bound = date2num(datetime(year + 1, 1, 1, 0, 0),
+                                 time.units, time.dtype)
+        elif freq == 'dec':
+            min_bound = date2num(datetime(year, 1, 1, 0, 0),
+                                 time.units, time.dtype)
+            max_bound = date2num(datetime(year + 10, 1, 1, 0, 0),
+                                 time.units, time.dtype)
+        else:
+            delta = {
+                'day': 12.0 / 24,
+                '6hr': 3.0 / 24,
+                '3hr': 1.5 / 24,
+                '1hr': 0.5 / 24,
+            }
+            if freq not in delta:
+                raise NotImplementedError(
+                    f"Cannot guess time bounds for frequency '{freq}'"
+                )
+            point = time.points[step]
+            min_bound = point - delta[freq]
+            max_bound = point + delta[freq]
+        bounds.append([min_bound, max_bound])
+
+    return np.array(bounds)
+
+
+class GenericFix(Fix):
+    """Class providing generic fixes for all datasets."""
+
+    def fix_metadata(self, cubes: Sequence[Cube]) -> CubeList:
+        """Fix cube metadata.
+
+        Parameters
+        ----------
+        cubes:
+            Cubes to be fixed.
+
+        Returns
+        -------
+        CubeList
+            Fixed cubes.
+
+        """
+        # Make sure the this fix also works when no extra_facets are given
+        if 'project' in self.extra_facets and 'dataset' in self.extra_facets:
+            dataset_str = (
+                f"{self.extra_facets['project']}:"
+                f"{self.extra_facets['dataset']}"
+            )
+        else:
+            dataset_str = None
+
+        # The following fixes are designed to operate on the actual cube that
+        # corresponds to the variable. Thus, it needs to be assured (possibly
+        # by prior dataset-specific fixes) that the cubes here contain only one
+        # relevant cube.
+        cube = _get_single_cube(
+            cubes, self.vardef.short_name, dataset_str=dataset_str
+        )
+
+        cube = self._fix_standard_name(cube)
+        cube = self._fix_long_name(cube)
+        cube = self._fix_psu_units(cube)
+        cube = self._fix_units(cube)
+
+        cube = self._fix_regular_coord_names(cube)
+        cube = self._fix_alternative_generic_level_coords(cube)
+        cube = self._fix_coords(cube)
+        cube = self._fix_time_coord(cube)
+
+        return CubeList([cube])
+
+    def fix_data(self, cube: Cube) -> Cube:
+        """Fix cube data.
+
+        Parameters
+        ----------
+        cube:
+            Cube to be fixed.
+
+        Returns
+        -------
+        Cube
+            Fixed cube.
+
+        """
+        return cube
+
+    @staticmethod
+    def _msg_suffix(cube: Cube) -> str:
+        """Get prefix for log messages."""
+        if 'source_file' in cube.attributes:
+            return f"\n(for file {cube.attributes['source_file']})"
+        return f"\n(for variable {cube.var_name})"
+
+    def _debug_msg(self, cube: Cube, msg: str, *args) -> None:
+        """Print debug message."""
+        msg += self._msg_suffix(cube)
+        logger.debug(msg, *args)
+
+    def _warning_msg(self, cube: Cube, msg: str, *args) -> None:
+        """Print debug message."""
+        msg += self._msg_suffix(cube)
+        logger.warning(msg, *args)
+
+    @staticmethod
+    def _set_range_in_0_360(array: np.ndarray) -> np.ndarray:
+        """Convert longitude coordinate to [0, 360]."""
+        return (array + 360.0) % 360.0
+
+    def _reverse_coord(self, cube: Cube, coord: Coord) -> tuple[Cube, Coord]:
+        """Reverse cube along a given coordinate."""
+        if coord.ndim == 1:
+            cube = reverse(cube, cube.coord_dims(coord))
+            coord = cube.coord(var_name=coord.var_name)
+            if coord.has_bounds():
+                bounds = coord.core_bounds()
+                right_bounds = bounds[:-2, 1]
+                left_bounds = bounds[1:-1, 0]
+                if np.all(right_bounds != left_bounds):
+                    coord.bounds = np.fliplr(bounds)
+            self._debug_msg(
+                cube,
+                "Coordinate %s values have been reversed",
+                coord.var_name,
+            )
+        return (cube, coord)
+
+    def _get_effective_units(self) -> str:
+        """Get effective units."""
+        if self.vardef.units.lower() == 'psu':
+            return '1'
+        return self.vardef.units
+
+    def _fix_units(self, cube: Cube) -> Cube:
+        """Fix cube units."""
+        if self.vardef.units:
+            units = self._get_effective_units()
+
+            # We use str(cube.units) in the following to catch `degrees` !=
+            # `degrees_north`
+            if str(cube.units) != units:
+                old_units = cube.units
+                try:
+                    cube.convert_units(units)
+                except (ValueError, UnitConversionError):
+                    self._warning_msg(
+                        cube,
+                        "Failed to convert cube units from '%s' to '%s'",
+                        old_units,
+                        units,
+                    )
+                else:
+                    self._warning_msg(
+                        cube,
+                        "Converted cube units from '%s' to '%s'",
+                        old_units,
+                        units,
+                    )
+        return cube
+
+    def _fix_standard_name(self, cube: Cube) -> Cube:
+        """Fix standard_name."""
+        # Do not change empty standard names
+        if not self.vardef.standard_name:
+            return cube
+
+        if cube.standard_name != self.vardef.standard_name:
+            self._warning_msg(
+                cube,
+                "Standard name changed from '%s' to '%s'",
+                cube.standard_name,
+                self.vardef.standard_name,
+            )
+            cube.standard_name = self.vardef.standard_name
+
+        return cube
+
+    def _fix_long_name(self, cube: Cube) -> Cube:
+        """Fix long_name."""
+        # Do not change empty long names
+        if not self.vardef.long_name:
+            return cube
+
+        if cube.long_name != self.vardef.long_name:
+            self._warning_msg(
+                cube,
+                "Long name changed from '%s' to '%s'",
+                cube.long_name,
+                self.vardef.long_name,
+            )
+            cube.long_name = self.vardef.long_name
+
+        return cube
+
+    def _fix_psu_units(self, cube: Cube) -> Cube:
+        """Fix psu units."""
+        if cube.attributes.get('invalid_units', '').lower() == 'psu':
+            cube.units = '1'
+            cube.attributes.pop('invalid_units')
+            self._debug_msg(cube, "Units converted from 'psu' to '1'")
+        return cube
+
+    def _fix_regular_coord_names(self, cube: Cube) -> Cube:
+        """Fix regular (non-generic-level) coordinate names."""
+        for cmor_coord in self.vardef.coordinates.values():
+            if cmor_coord.generic_level:
+                continue  # Ignore generic level coordinate in this function
+            if cube.coords(var_name=cmor_coord.out_name):
+                continue  # Coordinate found -> fine here
+            if cube.coords(cmor_coord.standard_name):
+                cube_coord = cube.coord(cmor_coord.standard_name)
+                self._fix_cmip6_multidim_lat_lon_coord(
+                    cube, cmor_coord, cube_coord
+                )
+        return cube
+
+    def _fix_alternative_generic_level_coords(self, cube: Cube) -> Cube:
+        """Fix alternative generic level coordinates."""
+        # Avoid overriding existing variable information
+        cmor_var_coordinates = self.vardef.coordinates.copy()
+        for (coord_name, cmor_coord) in cmor_var_coordinates.items():
+            if not cmor_coord.generic_level:
+                continue  # Ignore non-generic-level coordinates
+            if not cmor_coord.generic_lev_coords:
+                continue  # Cannot fix anything without coordinate info
+
+            # Extract names of the actual generic level coordinates present in
+            # the cube (e.g., `hybrid_height`, `standard_hybrid_sigma`)
+            (standard_name, out_name, name) = _get_generic_lev_coord_names(
+                cube, cmor_coord
+            )
+
+            # Make sure to update variable information with actual generic
+            # level coordinate if one has been found; this is necessary for
+            # subsequent fixes
+            if standard_name:
+                new_generic_level_coord = _get_new_generic_level_coord(
+                    self.vardef, cmor_coord, coord_name, name
+                )
+                self.vardef.coordinates[coord_name] = new_generic_level_coord
+                self._debug_msg(
+                    cube,
+                    "Generic level coordinate %s will be checked against %s "
+                    "coordinate information",
+                    coord_name,
+                    name,
+                )
+
+            # If a generic level coordinate has been found, we don't need to
+            # look for alternatives
+            if standard_name or out_name:
+                continue
+
+            # Search for alternative coordinates (i.e., regular level
+            # coordinates); if none found, do nothing
+            try:
+                (alternative_coord,
+                 cube_coord) = _get_alternative_generic_lev_coord(
+                    cube, coord_name, self.vardef.table_type
+                )
+            except ValueError:  # no alternatives found
+                continue
+
+            # Fix alternative coord
+            (cube, cube_coord) = self._fix_coord(
+                cube, alternative_coord, cube_coord
+            )
+
+        return cube
+
+    def _fix_cmip6_multidim_lat_lon_coord(
+        self,
+        cube: Cube,
+        cmor_coord: CoordinateInfo,
+        cube_coord: Coord,
+    ) -> None:
+        """Fix CMIP6 multidimensional latitude and longitude coordinates."""
+        is_cmip6_multidim_lat_lon = all([
+            'CMIP6' in self.vardef.table_type,
+            cube_coord.ndim > 1,
+            cube_coord.standard_name in ('latitude', 'longitude'),
+        ])
+        if is_cmip6_multidim_lat_lon:
+            self._debug_msg(
+                cube,
+                "Multidimensional %s coordinate is not set in CMOR standard, "
+                "ESMValTool will change the original value of '%s' to '%s' to "
+                "match the one-dimensional case",
+                cube_coord.standard_name,
+                cube_coord.var_name,
+                cmor_coord.out_name,
+            )
+            cube_coord.var_name = cmor_coord.out_name
+
+    def _fix_coord_units(
+        self,
+        cube: Cube,
+        cmor_coord: CoordinateInfo,
+        cube_coord: Coord,
+    ) -> None:
+        """Fix coordinate units."""
+        if not cmor_coord.units:
+            return
+
+        # We use str(cube_coord.units) in the following to catch `degrees` !=
+        # `degrees_north`
+        if str(cube_coord.units) != cmor_coord.units:
+            old_units = cube_coord.units
+            try:
+                cube_coord.convert_units(cmor_coord.units)
+            except (ValueError, UnitConversionError):
+                self._warning_msg(
+                    cube,
+                    "Failed to convert units of coordinate %s from '%s' to "
+                    "'%s'",
+                    cmor_coord.out_name,
+                    old_units,
+                    cmor_coord.units,
+                )
+            else:
+                self._warning_msg(
+                    cube,
+                    "Coordinate %s units '%s' converted to '%s'",
+                    cmor_coord.out_name,
+                    old_units,
+                    cmor_coord.units,
+                )
+
+    def _fix_requested_coord_values(
+        self,
+        cube: Cube,
+        cmor_coord: CoordinateInfo,
+        cube_coord: Coord,
+    ) -> None:
+        """Fix requested coordinate values."""
+        if not cmor_coord.requested:
+            return
+
+        # Cannot fix non-1D points
+        if cube_coord.core_points().ndim != 1:
+            return
+
+        # Get requested CMOR values
+        try:
+            cmor_points = np.array(cmor_coord.requested, dtype=float)
+        except ValueError:
+            return
+
+        # Align coordinate points with CMOR values if possible
+        if cube_coord.core_points().shape != cmor_points.shape:
+            return
+        atol = 1e-7 * np.mean(cmor_points)
+        align_coords = np.allclose(
+            cube_coord.core_points(),
+            cmor_points,
+            rtol=1e-7,
+            atol=atol,
+        )
+        if align_coords:
+            cube_coord.points = cmor_points
+            self._debug_msg(
+                cube,
+                "Aligned %s points with CMOR points",
+                cmor_coord.out_name,
+            )
+
+    def _fix_longitude_0_360(
+        self,
+        cube: Cube,
+        cmor_coord: CoordinateInfo,
+        cube_coord: Coord,
+    ) -> tuple[Cube, Coord]:
+        """Fix longitude coordinate to be in [0, 360]."""
+        if not cube_coord.standard_name == 'longitude':
+            return (cube, cube_coord)
+
+        # Only apply fixes when values are outside of valid range [0, 360]
+        inside_0_360 = all([
+            cube_coord.core_points().min() >= 0.0,
+            cube_coord.core_points().max() <= 360.0,
+        ])
+        if inside_0_360:
+            return (cube, cube_coord)
+
+        # Cannot fix longitudes outside [-360, 720]
+        if np.any(cube_coord.core_points() < -360.0):
+            return (cube, cube_coord)
+        if np.any(cube_coord.core_points() > 720.0):
+            return (cube, cube_coord)
+
+        # cube.intersection only works for cells with 0 or 2 bounds
+        # Note: nbounds==0 means there are no bounds given, nbounds==2
+        # implies a regular grid with bounds in the grid direction,
+        # nbounds>2 implies an irregular grid with bounds given as vertices
+        # of the cell polygon.
+        if cube_coord.ndim == 1 and cube_coord.nbounds in (0, 2):
+            lon_extent = CoordExtent(cube_coord, 0.0, 360., True, False)
+            cube = cube.intersection(lon_extent)
+        else:
+            new_lons = cube_coord.core_points().copy()
+            new_lons = self._set_range_in_0_360(new_lons)
+
+            if cube_coord.core_bounds() is None:
+                new_bounds = None
+            else:
+                new_bounds = cube_coord.core_bounds().copy()
+                new_bounds = self._set_range_in_0_360(new_bounds)
+
+            new_coord = cube_coord.copy(new_lons, new_bounds)
+            dims = cube.coord_dims(cube_coord)
+            cube.remove_coord(cube_coord)
+            cube.add_aux_coord(new_coord, dims)
+        new_coord = cube.coord(var_name=cmor_coord.out_name)
+        self._debug_msg(cube, "Shifted longitude to [0, 360]")
+
+        return (cube, new_coord)
+
+    def _fix_coord_bounds(
+        self,
+        cube: Cube,
+        cmor_coord: CoordinateInfo,
+        cube_coord: Coord,
+    ) -> None:
+        """Fix coordinate bounds."""
+        if cmor_coord.must_have_bounds != 'yes' or cube_coord.has_bounds():
+            return
+
+        # Skip guessing bounds for unstructured grids
+        if _is_unstructured_grid(cube) and cube_coord.standard_name in (
+                'latitude', 'longitude'):
+            self._debug_msg(
+                cube,
+                "Will not guess bounds for coordinate %s of unstructured grid",
+                cube_coord.var_name,
+            )
+            return
+
+        try:
+            cube_coord.guess_bounds()
+            self._warning_msg(
+                cube,
+                "Added guessed bounds to coordinate %s",
+                cube_coord.var_name,
+            )
+        except ValueError as exc:
+            self._warning_msg(
+                cube,
+                "Cannot guess bounds for coordinate %s: %s",
+                cube.var_name,
+                str(exc),
+            )
+
+    def _fix_coord_direction(
+        self,
+        cube: Cube,
+        cmor_coord: CoordinateInfo,
+        cube_coord: Coord,
+    ) -> tuple[Cube, Coord]:
+        """Fix coordinate direction (increasing vs. decreasing)."""
+        # Skip fix for a variety of reasons
+        if cube_coord.ndim > 1:
+            return (cube, cube_coord)
+        if cube_coord.dtype.kind == 'U':
+            return (cube, cube_coord)
+        if _is_unstructured_grid(cube) and cube_coord.standard_name in (
+                'latitude', 'longitude'
+        ):
+            return (cube, cube_coord)
+        if len(cube_coord.core_points()) == 1:
+            return (cube, cube_coord)
+        if not cmor_coord.stored_direction:
+            return (cube, cube_coord)
+
+        # Fix coordinates with wrong direction
+        if cmor_coord.stored_direction == 'increasing':
+            if cube_coord.core_points()[0] > cube_coord.core_points()[1]:
+                (cube, cube_coord) = self._reverse_coord(cube, cube_coord)
+        elif cmor_coord.stored_direction == 'decreasing':
+            if cube_coord.core_points()[0] < cube_coord.core_points()[1]:
+                (cube, cube_coord) = self._reverse_coord(cube, cube_coord)
+
+        return (cube, cube_coord)
+
+    def _fix_time_units(self, cube: Cube, cube_coord: Coord) -> None:
+        """Fix time units in cube and attributes."""
+        # Fix cube units
+        old_units = cube_coord.units
+        cube_coord.convert_units(
+            Unit(
+                'days since 1850-1-1 00:00:00',
+                calendar=cube_coord.units.calendar,
+            )
+        )
+        simplified_cal = _get_simplified_calendar(cube_coord.units.calendar)
+        cube_coord.units = Unit(
+            cube_coord.units.origin, calendar=simplified_cal
+        )
+
+        # Fix units of time-related cube attributes
+        attrs = cube.attributes
+        parent_time = 'parent_time_units'
+        if parent_time in attrs:
+            if attrs[parent_time] in 'no parent':
+                pass
+            else:
+                try:
+                    parent_units = Unit(attrs[parent_time], simplified_cal)
+                except ValueError:
+                    pass
+                else:
+                    attrs[parent_time] = 'days since 1850-1-1 00:00:00'
+
+                    branch_parent = 'branch_time_in_parent'
+                    if branch_parent in attrs:
+                        attrs[branch_parent] = parent_units.convert(
+                            attrs[branch_parent], cube_coord.units)
+
+                    branch_child = 'branch_time_in_child'
+                    if branch_child in attrs:
+                        attrs[branch_child] = old_units.convert(
+                            attrs[branch_child], cube_coord.units)
+
+    def _fix_time_bounds(self, cube: Cube, cube_coord: Coord) -> None:
+        """Fix time bounds."""
+        times = {'time', 'time1', 'time2', 'time3'}
+        key = times.intersection(self.vardef.coordinates)
+        cmor = self.vardef.coordinates[' '.join(key)]
+        if cmor.must_have_bounds == 'yes' and not cube_coord.has_bounds():
+            cube_coord.bounds = get_time_bounds(cube_coord, self.frequency)
+            self._warning_msg(
+                cube,
+                "Added guessed bounds to coordinate %s",
+                cube_coord.var_name,
+            )
+
+    def _fix_time_coord(self, cube: Cube) -> Cube:
+        """Fix time coordinate."""
+        # Make sure to get dimensional time coordinate if possible
+        if cube.coords('time', dim_coords=True):
+            cube_coord = cube.coord('time', dim_coords=True)
+        elif cube.coords('time'):
+            cube_coord = cube.coord('time')
+        else:
+            return cube
+
+        # Cannot fix wrong time that are not references
+        if not cube_coord.units.is_time_reference():
+            return cube
+
+        # Fix time units
+        self._fix_time_units(cube, cube_coord)
+
+        # Remove time_origin from coordinate attributes
+        cube_coord.attributes.pop('time_origin', None)
+
+        # Fix time bounds
+        self._fix_time_bounds(cube, cube_coord)
+
+        return cube
+
+    def _fix_coord(
+        self,
+        cube: Cube,
+        cmor_coord: CoordinateInfo,
+        cube_coord: Coord,
+    ) -> tuple[Cube, Coord]:
+        """Fix non-time coordinate."""
+        self._fix_coord_units(cube, cmor_coord, cube_coord)
+        (cube, cube_coord) = self._fix_longitude_0_360(
+            cube, cmor_coord, cube_coord
+        )
+        self._fix_coord_bounds(cube, cmor_coord, cube_coord)
+        (cube, cube_coord) = self._fix_coord_direction(
+            cube, cmor_coord, cube_coord
+        )
+        self._fix_requested_coord_values(cube, cmor_coord, cube_coord)
+        return (cube, cube_coord)
+
+    def _fix_coords(self, cube: Cube) -> Cube:
+        """Fix non-time coordinates."""
+        for cmor_coord in self.vardef.coordinates.values():
+
+            # Cannot fix generic level coords with no unique CMOR information
+            if cmor_coord.generic_level and not cmor_coord.out_name:
+                continue
+
+            # Try to get coordinate from cube; if it does not exists, skip
+            if not cube.coords(var_name=cmor_coord.out_name):
+                continue
+            cube_coord = cube.coord(var_name=cmor_coord.out_name)
+
+            # Fixes for time coord are done separately
+            if cube_coord.var_name == 'time':
+                continue
+
+            # Fixes
+            (cube, cube_coord) = self._fix_coord(cube, cmor_coord, cube_coord)
+
+        return cube
diff --git a/esmvalcore/cmor/_utils.py b/esmvalcore/cmor/_utils.py
new file mode 100644
index 000000000..4b083f19d
--- /dev/null
+++ b/esmvalcore/cmor/_utils.py
@@ -0,0 +1,219 @@
+"""Utilities for CMOR module."""
+from __future__ import annotations
+
+import logging
+from collections.abc import Sequence
+from typing import Optional
+
+from iris.coords import Coord
+from iris.cube import Cube
+from iris.exceptions import CoordinateNotFoundError
+
+from esmvalcore.cmor.table import CMOR_TABLES, CoordinateInfo, VariableInfo
+
+logger = logging.getLogger(__name__)
+
+_ALTERNATIVE_GENERIC_LEV_COORDS = {
+    'alevel': {
+        'CMIP5': ['alt40', 'plevs'],
+        'CMIP6': ['alt16', 'plev3'],
+        'obs4MIPs': ['alt16', 'plev3'],
+    },
+    'zlevel': {
+        'CMIP3': ['pressure'],
+    },
+}
+
+
+def _get_alternative_generic_lev_coord(
+    cube: Cube,
+    coord_name: str,
+    cmor_table_type: str,
+) -> tuple[CoordinateInfo, Coord]:
+    """Find alternative generic level coordinate in cube.
+
+    Parameters
+    ----------
+    cube:
+        Cube to be checked.
+    coord_name:
+        Name of the generic level coordinate.
+    cmor_table_type:
+        CMOR table type, e.g., CMIP3, CMIP5, CMIP6. Note: This is NOT the
+        project of the dataset, but rather the entry `cmor_type` in
+        `config-developer.yml`.
+
+    Returns
+    -------
+    tuple[CoordinateInfo, Coord]
+        Coordinate information from the CMOR tables and the corresponding
+        coordinate in the cube.
+
+    Raises
+    ------
+    ValueError
+        No valid alternative generic level coordinate present in cube.
+
+    """
+    alternatives_for_coord = _ALTERNATIVE_GENERIC_LEV_COORDS.get(
+        coord_name, {}
+    )
+    allowed_alternatives = alternatives_for_coord.get(cmor_table_type, [])
+
+    # Check if any of the allowed alternative coordinates is present in the
+    # cube
+    for allowed_alternative in allowed_alternatives:
+        cmor_coord = CMOR_TABLES[cmor_table_type].coords[allowed_alternative]
+        if cube.coords(var_name=cmor_coord.out_name):
+            cube_coord = cube.coord(var_name=cmor_coord.out_name)
+            return (cmor_coord, cube_coord)
+
+    raise ValueError(
+        f"Found no valid alternative coordinate for generic level coordinate "
+        f"'{coord_name}'"
+    )
+
+
+def _get_generic_lev_coord_names(
+    cube: Cube,
+    cmor_coord: CoordinateInfo,
+) -> tuple[str | None, str | None, str | None]:
+    """Try to get names of a generic level coordinate.
+
+    Parameters
+    ----------
+    cube:
+        Cube to be checked.
+    cmor_coord:
+        Coordinate information from the CMOR table with a non-emmpty
+        `generic_lev_coords` :obj:`dict`.
+
+    Returns
+    -------
+    tuple[str | None, str | None, str | None]
+        Tuple of `standard_name`, `out_name`, and `name` of the generic level
+        coordinate present in the cube. Values are ``None`` if generic level
+        coordinate has not been found in cube.
+
+    """
+    standard_name = None
+    out_name = None
+    name = None
+
+    # Iterate over all possible generic level coordinates
+    for coord in cmor_coord.generic_lev_coords.values():
+        # First, try to use var_name to find coordinate
+        if cube.coords(var_name=coord.out_name):
+            cube_coord = cube.coord(var_name=coord.out_name)
+            out_name = coord.out_name
+            if cube_coord.standard_name == coord.standard_name:
+                standard_name = coord.standard_name
+                name = coord.name
+
+        # Second, try to use standard_name to find coordinate
+        elif cube.coords(coord.standard_name):
+            standard_name = coord.standard_name
+            name = coord.name
+
+    return (standard_name, out_name, name)
+
+
+def _get_new_generic_level_coord(
+    var_info: VariableInfo,
+    generic_level_coord: CoordinateInfo,
+    generic_level_coord_name: str,
+    new_coord_name: str | None,
+) -> CoordinateInfo:
+    """Get new generic level coordinate.
+
+    There are a variety of possible options for each generic level coordinate
+    (e.g., `alevel`) which is actually present in a cube, for example,
+    `hybrid_height` or `standard_hybrid_sigma`. This function returns the new
+    coordinate (e.g., `new_coord_name=hybrid_height`) with the relevant
+    metadata.
+
+    Note
+    ----
+    This alters the corresponding entry of the original generic level
+    coordinate's `generic_level_coords` attribute (i.e.,
+    ``generic_level_coord.generic_level_coords[new_coord_name]`) in-place!
+
+    Parameters
+    ----------
+    var_info:
+        CMOR variable information.
+    generic_level_coord:
+        Original generic level coordinate.
+    generic_level_coord_name:
+        Original name of the generic level coordinate (e.g., `alevel`).
+    new_coord_name:
+        Name of the new generic level coordinate (e.g., `hybrid_height`).
+
+    Returns
+    -------
+    CoordinateInfo
+        New generic level coordinate.
+
+    """
+    new_coord = generic_level_coord.generic_lev_coords[new_coord_name]
+    new_coord.generic_level = True
+    new_coord.generic_lev_coords = (
+        var_info.coordinates[generic_level_coord_name].generic_lev_coords
+    )
+    return new_coord
+
+
+def _get_simplified_calendar(calendar: str) -> str:
+    """Simplify calendar."""
+    calendar_aliases = {
+        'all_leap': '366_day',
+        'noleap': '365_day',
+        'gregorian': 'standard',
+    }
+    return calendar_aliases.get(calendar, calendar)
+
+
+def _is_unstructured_grid(cube: Cube) -> bool:
+    """Check if cube uses unstructured grid."""
+    try:
+        lat = cube.coord('latitude')
+        lon = cube.coord('longitude')
+    except CoordinateNotFoundError:
+        pass
+    else:
+        if lat.ndim == 1 and (cube.coord_dims(lat) == cube.coord_dims(lon)):
+            return True
+    return False
+
+
+def _get_single_cube(
+    cube_list: Sequence[Cube],
+    short_name: str,
+    dataset_str: Optional[str] = None,
+) -> Cube:
+    if len(cube_list) == 1:
+        return cube_list[0]
+    cube = None
+    for raw_cube in cube_list:
+        if raw_cube.var_name == short_name:
+            cube = raw_cube
+            break
+
+    if dataset_str is None:
+        dataset_str = ''
+    else:
+        dataset_str = f' in {dataset_str}'
+
+    if not cube:
+        raise ValueError(
+            f"More than one cube found for variable {short_name}{dataset_str} "
+            f"but none of their var_names match the expected.\nFull list of "
+            f"cubes encountered: {cube_list}"
+        )
+    logger.warning(
+        "Found variable %s%s, but there were other present in the file. Those "
+        "extra variables are usually metadata (cell area, latitude "
+        "descriptions) that was not saved according to CF-conventions. It is "
+        "possible that errors appear further on because of this.\nFull list "
+        "of cubes encountered: %s", short_name, dataset_str, cube_list)
+    return cube
diff --git a/esmvalcore/cmor/check.py b/esmvalcore/cmor/check.py
index 4eb057730..43214168b 100644
--- a/esmvalcore/cmor/check.py
+++ b/esmvalcore/cmor/check.py
@@ -1,7 +1,12 @@
 """Module for checking iris cubes against their CMOR definitions."""
+from __future__ import annotations
+
 import logging
-from datetime import datetime
+import warnings
+from collections.abc import Callable
 from enum import IntEnum
+from functools import cached_property
+from typing import Optional
 
 import cf_units
 import iris.coord_categorisation
@@ -9,10 +14,18 @@ import iris.coords
 import iris.exceptions
 import iris.util
 import numpy as np
+from iris.cube import Cube
 
-from esmvalcore.iris_helpers import date2num
-
-from .table import CMOR_TABLES
+from esmvalcore.cmor._fixes.fix import GenericFix
+from esmvalcore.cmor._utils import (
+    _get_alternative_generic_lev_coord,
+    _get_generic_lev_coord_names,
+    _get_new_generic_level_coord,
+    _get_simplified_calendar,
+    _is_unstructured_grid,
+)
+from esmvalcore.cmor.table import get_var_info
+from esmvalcore.exceptions import ESMValCoreDeprecationWarning
 
 
 class CheckLevels(IntEnum):
@@ -34,49 +47,6 @@ class CheckLevels(IntEnum):
     """Do not fail for any discrepancy with CMOR standards."""
 
 
-def _get_next_month(month, year):
-    if month != 12:
-        return month + 1, year
-    return 1, year + 1
-
-
-def _get_time_bounds(time, freq):
-    bounds = []
-    dates = time.units.num2date(time.points)
-    for step, date in enumerate(dates):
-        month = date.month
-        year = date.year
-        if freq in ['mon', 'mo']:
-            next_month, next_year = _get_next_month(month, year)
-            min_bound = date2num(datetime(year, month, 1, 0, 0),
-                                 time.units, time.dtype)
-            max_bound = date2num(datetime(next_year, next_month, 1, 0, 0),
-                                 time.units, time.dtype)
-        elif freq == 'yr':
-            min_bound = date2num(datetime(year, 1, 1, 0, 0),
-                                 time.units, time.dtype)
-            max_bound = date2num(datetime(year + 1, 1, 1, 0, 0),
-                                 time.units, time.dtype)
-        elif freq == 'dec':
-            min_bound = date2num(datetime(year, 1, 1, 0, 0),
-                                 time.units, time.dtype)
-            max_bound = date2num(datetime(year + 10, 1, 1, 0, 0),
-                                 time.units, time.dtype)
-        else:
-            delta = {
-                'day': 12 / 24,
-                '6hr': 3 / 24,
-                '3hr': 1.5 / 24,
-                '1hr': 0.5 / 24,
-            }
-            point = time.points[step]
-            min_bound = point - delta[freq]
-            max_bound = point + delta[freq]
-        bounds.append([min_bound, max_bound])
-
-    return np.array(bounds)
-
-
 class CMORCheckError(Exception):
     """Exception raised when a cube does not pass the CMORCheck."""
 
@@ -84,9 +54,6 @@ class CMORCheckError(Exception):
 class CMORCheck():
     """Class used to check the CMOR-compliance of the data.
 
-    It can also fix some minor errors and does some minor data
-    homogeneization:
-
     Parameters
     ----------
     cube: iris.cube.Cube:
@@ -94,13 +61,23 @@ class CMORCheck():
     var_info: variables_info.VariableInfo
         Variable info to check.
     frequency: str
-        Expected frequency for the data.
+        Expected frequency for the data. If not given, use the one from the
+        variable information.
     fail_on_error: bool
         If true, CMORCheck stops on the first error. If false, it collects
         all possible errors before stopping.
     automatic_fixes: bool
         If True, CMORCheck will try to apply automatic fixes for any
         detected error, if possible.
+
+        .. deprecated:: 2.10.0
+            This option has been deprecated in ESMValCore version 2.10.0 and is
+            scheduled for removal in version 2.12.0. Please use the functions
+            :func:`~esmvalcore.preprocessor.fix_metadata`,
+            :func:`~esmvalcore.preprocessor.fix_data`, or
+            :meth:`esmvalcore.dataset.Dataset.load` (which automatically
+            includes the first two functions) instead. Fixes and CMOR checks
+            have been clearly separated in ESMValCore version 2.10.0.
     check_level: CheckLevels
         Level of strictness of the checks.
 
@@ -131,7 +108,6 @@ class CMORCheck():
         self._errors = list()
         self._warnings = list()
         self._debug_messages = list()
-        self._unstructured = None
 
         self._cmor_var = var_info
         if not frequency:
@@ -139,47 +115,61 @@ class CMORCheck():
         self.frequency = frequency
         self.automatic_fixes = automatic_fixes
 
-    def _is_unstructured_grid(self):
-        if self._unstructured is None:
-            self._unstructured = False
-            try:
-                lat = self._cube.coord('latitude')
-                lon = self._cube.coord('longitude')
-            except iris.exceptions.CoordinateNotFoundError:
-                pass
-            else:
-                if lat.ndim == 1 and (self._cube.coord_dims(lat)
-                                      == self._cube.coord_dims(lon)):
-                    self._unstructured = True
-        return self._unstructured
-
-    def check_metadata(self, logger=None):
+        # Deprecate automatic_fixes (remove in v2.12)
+        if automatic_fixes:
+            msg = (
+                "The option `automatic_fixes` has been deprecated in "
+                "ESMValCore version 2.10.0 and is scheduled for removal in "
+                "version 2.12.0. Please use the functions "
+                "esmvalcore.preprocessor.fix_metadata(), "
+                "esmvalcore.preprocessor.fix_data(), or "
+                "esmvalcore.dataset.Dataset.load() (which automatically "
+                "includes the first two functions) instead. Fixes and CMOR "
+                "checks have been clearly separated in ESMValCore version "
+                "2.10.0."
+            )
+            warnings.warn(msg, ESMValCoreDeprecationWarning)
+
+        # TODO: remove in v2.12
+
+        self._generic_fix = GenericFix(var_info, frequency=frequency)
+
+    @cached_property
+    def _unstructured_grid(self) -> bool:
+        """Cube uses unstructured grid."""
+        return _is_unstructured_grid(self._cube)
+
+    def check_metadata(self, logger: Optional[logging.Logger] = None) -> Cube:
         """Check the cube metadata.
 
-        Perform all the tests that do not require to have the data in memory.
-
-        It will also report some warnings in case of minor errors and
-        homogenize some data:
-
-            - Equivalent calendars will all default to the same name.
-            - Time units will be set to days since 1850-01-01
+        It will also report some warnings in case of minor errors.
 
 
         Parameters
         ----------
-        logger: logging.Logger
+        logger:
             Given logger.
 
+        Returns
+        -------
+        iris.cube.Cube
+            Checked cube.
+
         Raises
         ------
         CMORCheckError
             If errors are found. If fail_on_error attribute is set to True,
             raises as soon as an error is detected. If set to False, it perform
             all checks and then raises.
+
         """
         if logger is not None:
             self._logger = logger
 
+        # TODO: remove in v2.12
+        if self.automatic_fixes:
+            [self._cube] = self._generic_fix.fix_metadata([self._cube])
+
         self._check_var_metadata()
         self._check_fill_value()
         self._check_multiple_coords_same_stdname()
@@ -196,10 +186,9 @@ class CMORCheck():
 
         return self._cube
 
-    def check_data(self, logger=None):
+    def check_data(self, logger: Optional[logging.Logger] = None) -> Cube:
         """Check the cube data.
 
-        Performs all the tests that require to have the data in memory.
         Assumes that metadata is correct, so you must call check_metadata prior
         to this.
 
@@ -207,28 +196,35 @@ class CMORCheck():
 
         Parameters
         ----------
-        logger: logging.Logger
+        logger:
             Given logger.
 
+        Returns
+        -------
+        iris.cube.Cube
+            Checked cube.
+
         Raises
         ------
         CMORCheckError
             If errors are found. If fail_on_error attribute is set to True,
             raises as soon as an error is detected. If set to False, it perform
             all checks and then raises.
+
         """
         if logger is not None:
             self._logger = logger
 
-        if self._cmor_var.units:
-            units = self._get_effective_units()
-            if str(self._cube.units) != units:
-                self._cube.convert_units(units)
+        # TODO: remove in v2.12
+        if self.automatic_fixes:
+            self._cube = self._generic_fix.fix_data(self._cube)
 
         self._check_coords_data()
 
+        self.report_debug_messages()
         self.report_warnings()
         self.report_errors()
+
         return self._cube
 
     def report_errors(self):
@@ -251,13 +247,7 @@ class CMORCheck():
             raise CMORCheckError(msg)
 
     def report_warnings(self):
-        """Report detected warnings to the given logger.
-
-        Parameters
-        ----------
-        logger: logging.Logger
-            Given logger
-        """
+        """Report detected warnings to the given logger."""
         if self.has_warnings():
             msg = '\n'.join([
                 f'There were warnings in variable {self._cube.var_name}:',
@@ -268,13 +258,7 @@ class CMORCheck():
             self._logger.warning(msg)
 
     def report_debug_messages(self):
-        """Report detected debug messages to the given logger.
-
-        Parameters
-        ----------
-        logger: logging.Logger
-            Given logger.
-        """
+        """Report detected debug messages to the given logger."""
         if self.has_debug_messages():
             msg = '\n'.join([
                 f'There were metadata changes in variable '
@@ -298,49 +282,24 @@ class CMORCheck():
         # Check standard_name
         if self._cmor_var.standard_name:
             if self._cube.standard_name != self._cmor_var.standard_name:
-                if self.automatic_fixes:
-                    self.report_warning(
-                        'Standard name for {} changed from {} to {}',
-                        self._cube.var_name, self._cube.standard_name,
-                        self._cmor_var.standard_name)
-                    self._cube.standard_name = self._cmor_var.standard_name
-                else:
-                    self.report_error(self._attr_msg, self._cube.var_name,
-                                      'standard_name',
-                                      self._cmor_var.standard_name,
-                                      self._cube.standard_name)
+                self.report_error(self._attr_msg, self._cube.var_name,
+                                  'standard_name',
+                                  self._cmor_var.standard_name,
+                                  self._cube.standard_name)
         # Check long_name
         if self._cmor_var.long_name:
             if self._cube.long_name != self._cmor_var.long_name:
-                if self.automatic_fixes:
-                    self.report_warning(
-                        'Long name for {} changed from {} to {}',
-                        self._cube.var_name, self._cube.long_name,
-                        self._cmor_var.long_name)
-                    self._cube.long_name = self._cmor_var.long_name
-                else:
-                    self.report_error(self._attr_msg, self._cube.var_name,
-                                      'long_name', self._cmor_var.long_name,
-                                      self._cube.long_name)
+                self.report_error(self._attr_msg, self._cube.var_name,
+                                  'long_name', self._cmor_var.long_name,
+                                  self._cube.long_name)
 
         # Check units
-        if (self.automatic_fixes and self._cube.attributes.get(
-                'invalid_units', '').lower() == 'psu'):
-            self._cube.units = '1.0'
-            del self._cube.attributes['invalid_units']
-
         if self._cmor_var.units:
             units = self._get_effective_units()
             if self._cube.units != units:
-                if not self._cube.units.is_convertible(units):
-                    self.report_error(f'Variable {self._cube.var_name} units '
-                                      f'{self._cube.units} can not be '
-                                      f'converted to {self._cmor_var.units}')
-                else:
-                    self.report_warning(
-                        f'Variable {self._cube.var_name} units '
-                        f'{self._cube.units} will be '
-                        f'converted to {self._cmor_var.units}')
+                self.report_error(self._attr_msg, self._cube.var_name,
+                                  'units', self._cmor_var.units,
+                                  self._cube.units)
 
         # Check other variable attributes that match entries in cube.attributes
         attrs = ('positive', )
@@ -357,6 +316,7 @@ class CMORCheck():
 
     def _get_effective_units(self):
         """Get effective units."""
+        # TODO: remove entire function in v2.12
         if self._cmor_var.units.lower() == 'psu':
             units = '1.0'
         else:
@@ -423,20 +383,7 @@ class CMORCheck():
                 except iris.exceptions.CoordinateNotFoundError:
                     try:
                         coord = self._cube.coord(coordinate.standard_name)
-                        if self._cmor_var.table_type in 'CMIP6' and \
-                           coord.ndim > 1 and \
-                           coord.standard_name in ['latitude', 'longitude']:
-                            self.report_debug_message(
-                                'Multidimensional {0} coordinate is not set '
-                                'in CMOR standard. ESMValTool will change '
-                                'the original value of  {1} to {2} to match '
-                                'the one-dimensional case.',
-                                coordinate.standard_name,
-                                coord.var_name,
-                                coordinate.out_name,
-                            )
-                            coord.var_name = coordinate.out_name
-                        elif coord.standard_name in ['region', 'area_type']:
+                        if coord.standard_name in ['region', 'area_type']:
                             self.report_debug_message(
                                 'Coordinate {0} has var name {1} '
                                 'instead of {2}. '
@@ -467,33 +414,17 @@ class CMORCheck():
 
     def _check_generic_level_dim_names(self, key, coordinate):
         """Check name of generic level coordinate."""
-        standard_name = None
-        out_name = None
-        name = None
         if coordinate.generic_lev_coords:
-            for coord in coordinate.generic_lev_coords.values():
-                try:
-                    cube_coord = self._cube.coord(var_name=coord.out_name)
-                    out_name = coord.out_name
-                    if cube_coord.standard_name == coord.standard_name:
-                        standard_name = coord.standard_name
-                        name = coord.name
-                except iris.exceptions.CoordinateNotFoundError:
-                    try:
-                        cube_coord = self._cube.coord(
-                            var_name=coord.standard_name)
-                        standard_name = coord.standard_name
-                        name = coord.name
-                    except iris.exceptions.CoordinateNotFoundError:
-                        pass
+            (standard_name, out_name, name) = _get_generic_lev_coord_names(
+                self._cube, coordinate
+            )
             if standard_name:
                 if not out_name:
                     self.report_error(
                         f'Generic level coordinate {key} has wrong var_name.')
-                level = coordinate.generic_lev_coords[name]
-                level.generic_level = True
-                level.generic_lev_coords = self._cmor_var.coordinates[
-                    key].generic_lev_coords
+                level = _get_new_generic_level_coord(
+                    self._cmor_var, coordinate, key, name
+                )
                 self._cmor_var.coordinates[key] = level
                 self.report_debug_message(f'Generic level coordinate {key} '
                                           'will be checked against '
@@ -506,17 +437,6 @@ class CMORCheck():
                 else:
                     self._check_alternative_dim_names(key)
 
-    ALTERNATIVE_GENERIC_LEV_COORDS = {
-        'alevel': {
-            'CMIP5': ['alt40', 'plevs'],
-            'CMIP6': ['alt16', 'plev3'],
-            'obs4MIPs': ['alt16', 'plev3'],
-        },
-        'zlevel': {
-            'CMIP3': ['pressure'],
-        },
-    }
-
     def _check_alternative_dim_names(self, key):
         """Check for viable alternatives to generic level coordinates.
 
@@ -549,42 +469,34 @@ class CMORCheck():
         For ``cmor_strict=False`` project (like OBS) the check for requested
         values might be disabled.
         """
-        table_type = self._cmor_var.table_type
-        alternative_coord = None
-        allowed_alternatives = self.ALTERNATIVE_GENERIC_LEV_COORDS.get(
-            key, {}).get(table_type, [])
-
-        # Check if any of the allowed alternative coordinates is present in the
-        # cube
-        for allowed_alternative in allowed_alternatives:
-            coord_info = CMOR_TABLES[table_type].coords[allowed_alternative]
-            try:
-                cube_coord = self._cube.coord(var_name=coord_info.out_name)
-            except iris.exceptions.CoordinateNotFoundError:
-                pass
-            else:
-                if cube_coord.standard_name == coord_info.standard_name:
-                    alternative_coord = coord_info
-                    break
-                self.report_error(
-                    f"Found alternative coordinate '{coord_info.out_name}' "
-                    f"for generic level coordinate '{key}' with wrong "
-                    f"standard_name '{cube_coord.standard_name}' (expected "
-                    f"'{coord_info.standard_name}')")
-                break
+        try:
+            (alternative_coord,
+             cube_coord) = _get_alternative_generic_lev_coord(
+                self._cube, key, self._cmor_var.table_type
+            )
 
         # No valid alternative coordinate found -> critical error
-        if alternative_coord is None:
+        except ValueError:
             self.report_critical(self._does_msg, key, 'exist')
             return
 
+        # Wrong standard_name -> error
+        if cube_coord.standard_name != alternative_coord.standard_name:
+            self.report_error(
+                f"Found alternative coordinate '{alternative_coord.out_name}' "
+                f"for generic level coordinate '{key}' with wrong "
+                f"standard_name {cube_coord.standard_name}' (expected "
+                f"'{alternative_coord.standard_name}')"
+            )
+            return
+
         # Valid alternative coordinate found -> perform checks on it
         self.report_warning(
             f"Found alternative coordinate '{alternative_coord.out_name}' "
             f"for generic level coordinate '{key}'. Subsequent warnings about "
             f"levels that are not contained in '{alternative_coord.out_name}' "
             f"can be safely ignored.")
-        self._check_coord(alternative_coord, cube_coord, self._cube.var_name)
+        self._check_coord(alternative_coord, cube_coord, cube_coord.var_name)
 
     def _check_coords(self):
         """Check coordinates."""
@@ -616,6 +528,12 @@ class CMORCheck():
             except iris.exceptions.CoordinateNotFoundError:
                 continue
 
+            # TODO: remove in v2.12
+            if self.automatic_fixes:
+                (self._cube, coord) = self._generic_fix._fix_coord_direction(
+                    self._cube, coordinate, coord
+                )
+
             self._check_coord_monotonicity_and_direction(
                 coordinate, coord, var_name)
 
@@ -625,57 +543,24 @@ class CMORCheck():
             return
         if cmor.units:
             if str(coord.units) != cmor.units:
-                fixed = False
-                if self.automatic_fixes:
-                    try:
-                        old_unit = coord.units
-                        new_unit = cf_units.Unit(cmor.units,
-                                                 coord.units.calendar)
-                        coord.convert_units(new_unit)
-                        fixed = True
-                        self.report_warning(
-                            f'Coordinate {coord.var_name} units '
-                            f'{str(old_unit)} '
-                            f'converted to {cmor.units}')
-                    except ValueError:
-                        pass
-                if not fixed:
-                    self.report_critical(self._attr_msg, var_name, 'units',
-                                         cmor.units, coord.units)
+                self.report_critical(self._attr_msg, var_name, 'units',
+                                     cmor.units, coord.units)
         self._check_coord_points(cmor, coord, var_name)
 
     def _check_coord_bounds(self, cmor, coord, var_name):
         if cmor.must_have_bounds == 'yes' and not coord.has_bounds():
-            if self.automatic_fixes:
-                try:
-                    coord.guess_bounds()
-                except ValueError as ex:
-                    self.report_warning(
-                        'Can not guess bounds for coordinate {0} '
-                        'from var {1}: {2}', coord.var_name, var_name, ex)
-                else:
-                    self.report_warning(
-                        'Added guessed bounds to coordinate {0} from var {1}',
-                        coord.var_name, var_name)
-            else:
-                self.report_warning(
-                    'Coordinate {0} from var {1} does not have bounds',
-                    coord.var_name, var_name)
+            self.report_warning(
+                'Coordinate {0} from var {1} does not have bounds',
+                coord.var_name, var_name)
 
-    def _check_time_bounds(self, freq, time):
+    def _check_time_bounds(self, time):
         times = {'time', 'time1', 'time2', 'time3'}
         key = times.intersection(self._cmor_var.coordinates)
         cmor = self._cmor_var.coordinates[" ".join(key)]
         if cmor.must_have_bounds == 'yes' and not time.has_bounds():
-            if self.automatic_fixes:
-                time.bounds = _get_time_bounds(time, freq)
-                self.report_warning(
-                    'Added guessed bounds to coordinate {0} from var {1}',
-                    time.var_name, self._cmor_var.short_name)
-            else:
-                self.report_warning(
-                    'Coordinate {0} from var {1} does not have bounds',
-                    time.var_name, self._cmor_var.short_name)
+            self.report_warning(
+                'Coordinate {0} from var {1} does not have bounds',
+                time.var_name, self._cmor_var.short_name)
 
     def _check_coord_monotonicity_and_direction(self, cmor, coord, var_name):
         """Check monotonicity and direction of coordinate."""
@@ -684,8 +569,8 @@ class CMORCheck():
         if coord.dtype.kind == 'U':
             return
 
-        if self._is_unstructured_grid() and \
-           coord.standard_name in ['latitude', 'longitude']:
+        if (self._unstructured_grid and
+                coord.standard_name in ['latitude', 'longitude']):
             self.report_debug_message(
                 f'Coordinate {coord.standard_name} appears to belong to '
                 'an unstructured grid. Skipping monotonicity and '
@@ -694,118 +579,42 @@ class CMORCheck():
 
         if not coord.is_monotonic():
             self.report_critical(self._is_msg, var_name, 'monotonic')
+
         if len(coord.core_points()) == 1:
             return
+
         if cmor.stored_direction:
             if cmor.stored_direction == 'increasing':
                 if coord.core_points()[0] > coord.core_points()[1]:
-                    if not self.automatic_fixes or coord.ndim > 1:
-                        self.report_critical(self._is_msg, var_name,
-                                             'increasing')
-                    else:
-                        self._reverse_coord(coord)
+                    self.report_critical(self._is_msg, var_name, 'increasing')
             elif cmor.stored_direction == 'decreasing':
                 if coord.core_points()[0] < coord.core_points()[1]:
-                    if not self.automatic_fixes or coord.ndim > 1:
-                        self.report_critical(self._is_msg, var_name,
-                                             'decreasing')
-                    else:
-                        self._reverse_coord(coord)
-
-    def _reverse_coord(self, coord):
-        """Reverse coordinate."""
-        if coord.ndim == 1:
-            self._cube = iris.util.reverse(self._cube,
-                                           self._cube.coord_dims(coord))
-            reversed_coord = self._cube.coord(var_name=coord.var_name)
-            if reversed_coord.has_bounds():
-                bounds = reversed_coord.bounds
-                right_bounds = bounds[:-2, 1]
-                left_bounds = bounds[1:-1, 0]
-                if np.all(right_bounds != left_bounds):
-                    reversed_coord.bounds = np.fliplr(bounds)
-                    coord = reversed_coord
-            self.report_debug_message(f'Coordinate {coord.var_name} values'
-                                      'have been reversed.')
+                    self.report_critical(self._is_msg, var_name, 'decreasing')
 
     def _check_coord_points(self, coord_info, coord, var_name):
         """Check coordinate points: values, bounds and monotonicity."""
         # Check requested coordinate values exist in coord.points
         self._check_requested_values(coord, coord_info, var_name)
 
-        l_fix_coord_value = False
-
         # Check coordinate value ranges
         if coord_info.valid_min:
             valid_min = float(coord_info.valid_min)
             if np.any(coord.core_points() < valid_min):
-                if coord_info.standard_name == 'longitude' and \
-                        self.automatic_fixes:
-                    l_fix_coord_value = self._check_longitude_min(
-                        coord, var_name)
-                else:
-                    self.report_critical(self._vals_msg, var_name,
-                                         '< {} ='.format('valid_min'),
-                                         valid_min)
+                self.report_critical(self._vals_msg, var_name,
+                                     '< {} ='.format('valid_min'),
+                                     valid_min)
 
         if coord_info.valid_max:
             valid_max = float(coord_info.valid_max)
             if np.any(coord.core_points() > valid_max):
-                if coord_info.standard_name == 'longitude' and \
-                        self.automatic_fixes:
-                    l_fix_coord_value = self._check_longitude_max(
-                        coord, var_name)
-                else:
-                    self.report_critical(self._vals_msg, var_name,
-                                         '> {} ='.format('valid_max'),
-                                         valid_max)
-
-        if l_fix_coord_value:
-            # cube.intersection only works for cells with 0 or 2 bounds
-            # Note: nbounds==0 means there are no bounds given, nbounds==2
-            # implies a regular grid with bounds in the grid direction,
-            # nbounds>2 implies an irregular grid with bounds given as vertices
-            # of the cell polygon.
-            if coord.ndim == 1 and coord.nbounds in (0, 2):
-                lon_extent = iris.coords.CoordExtent(coord, 0.0, 360., True,
-                                                     False)
-                self._cube = self._cube.intersection(lon_extent)
-            else:
-                new_lons = coord.core_points().copy()
-                new_lons = self._set_range_in_0_360(new_lons)
-                if coord.core_bounds() is not None:
-                    new_bounds = coord.core_bounds().copy()
-                    new_bounds = self._set_range_in_0_360(new_bounds)
-                else:
-                    new_bounds = None
-                new_coord = coord.copy(new_lons, new_bounds)
-                dims = self._cube.coord_dims(coord)
-                self._cube.remove_coord(coord)
-                self._cube.add_aux_coord(new_coord, dims)
-            coord = self._cube.coord(var_name=var_name)
+                self.report_critical(self._vals_msg, var_name,
+                                     '> {} ='.format('valid_max'),
+                                     valid_max)
+
         self._check_coord_bounds(coord_info, coord, var_name)
         self._check_coord_monotonicity_and_direction(coord_info, coord,
                                                      var_name)
 
-    def _check_longitude_max(self, coord, var_name):
-        if np.any(coord.core_points() > 720):
-            self.report_critical(
-                f'{var_name} longitude coordinate has values > 720 degrees')
-            return False
-        return True
-
-    def _check_longitude_min(self, coord, var_name):
-        if np.any(coord.core_points() < -360):
-            self.report_critical(
-                f'{var_name} longitude coordinate has values < -360 degrees')
-            return False
-        return True
-
-    @staticmethod
-    def _set_range_in_0_360(array):
-        """Convert longitude coordinate to [0, 360]."""
-        return (array + 360.0) % 360.0
-
     def _check_requested_values(self, coord, coord_info, var_name):
         """Check requested values."""
         if coord_info.requested:
@@ -818,17 +627,6 @@ class CMORCheck():
                 cmor_points = np.array(coord_info.requested, dtype=float)
             except ValueError:
                 cmor_points = coord_info.requested
-            else:
-                atol = 1e-7 * np.mean(cmor_points)
-                if (self.automatic_fixes
-                        and coord.core_points().shape == cmor_points.shape
-                        and np.allclose(
-                            coord.core_points(),
-                            cmor_points,
-                            rtol=1e-7,
-                            atol=atol,
-                        )):
-                    coord.points = cmor_points
             for point in cmor_points:
                 if point not in coord.core_points():
                     self.report_warning(self._contain_msg, var_name,
@@ -853,12 +651,7 @@ class CMORCheck():
             self.report_critical(self._does_msg, var_name,
                                  'have time reference units')
         else:
-            old_units = coord.units
-            coord.convert_units(
-                cf_units.Unit('days since 1850-1-1 00:00:00',
-                              calendar=coord.units.calendar))
-            simplified_cal = self._simplify_calendar(coord.units.calendar)
-            coord.units = cf_units.Unit(coord.units.origin, simplified_cal)
+            simplified_cal = _get_simplified_calendar(coord.units.calendar)
             attrs = self._cube.attributes
             parent_time = 'parent_time_units'
             if parent_time in attrs:
@@ -866,8 +659,7 @@ class CMORCheck():
                     pass
                 else:
                     try:
-                        parent_units = cf_units.Unit(attrs[parent_time],
-                                                     simplified_cal)
+                        cf_units.Unit(attrs[parent_time], simplified_cal)
                     except ValueError:
                         self.report_warning('Attribute parent_time_units has '
                                             'a wrong format and cannot be '
@@ -875,17 +667,8 @@ class CMORCheck():
                                             'be added to convert properly '
                                             'attributes branch_time_in_parent '
                                             'and branch_time_in_child.')
-                    else:
-                        attrs[parent_time] = 'days since 1850-1-1 00:00:00'
-                        branch_parent = 'branch_time_in_parent'
-                        if branch_parent in attrs:
-                            attrs[branch_parent] = parent_units.convert(
-                                attrs[branch_parent], coord.units)
-                        branch_child = 'branch_time_in_child'
-                        if branch_child in attrs:
-                            attrs[branch_child] = old_units.convert(
-                                attrs[branch_child], coord.units)
 
+        # Check frequency
         tol = 0.001
         intervals = {'dec': (3600, 3660), 'day': (1, 1)}
         freq = self.frequency
@@ -941,18 +724,8 @@ class CMORCheck():
                     msg = '{}: Frequency {} does not match input data'
                     self.report_error(msg, var_name, freq)
                     break
-        self._check_time_bounds(freq, coord)
-        # remove time_origin from attributes
-        coord.attributes.pop('time_origin', None)
-
-    @staticmethod
-    def _simplify_calendar(calendar):
-        calendar_aliases = {
-            'all_leap': '366_day',
-            'noleap': '365_day',
-            'gregorian': 'standard',
-        }
-        return calendar_aliases.get(calendar, calendar)
+
+        self._check_time_bounds(coord)
 
     def has_errors(self):
         """Check if there are reported errors.
@@ -1071,30 +844,19 @@ class CMORCheck():
         self.report(CheckLevels.DEBUG, message, *args)
 
 
-def _get_cmor_checker(table,
-                      mip,
-                      short_name,
-                      frequency,
-                      fail_on_error=False,
-                      check_level=CheckLevels.DEFAULT,
-                      automatic_fixes=False):
-    """Get a CMOR checker/fixer."""
-    if table not in CMOR_TABLES:
-        raise NotImplementedError(
-            "No CMOR checker implemented for table {}."
-            "\nThe following options are available: {}".format(
-                table, ', '.join(CMOR_TABLES)))
-
-    cmor_table = CMOR_TABLES[table]
-    if table == 'CORDEX' and mip.endswith('hr'):
-        # CORDEX X-hourly tables define the mip
-        # as ending in 'h' instead of 'hr'.
-        mip = mip.replace('hr', 'h')
-    var_info = cmor_table.get_variable(mip, short_name)
-    if var_info is None:
-        var_info = CMOR_TABLES['custom'].get_variable(mip, short_name)
-
-    def _checker(cube):
+def _get_cmor_checker(
+    project: str,
+    mip: str,
+    short_name: str,
+    frequency: None | str = None,
+    fail_on_error: bool = False,
+    check_level: CheckLevels = CheckLevels.DEFAULT,
+    automatic_fixes: bool = False,  # TODO: remove in v2.12
+) -> Callable[[Cube], CMORCheck]:
+    """Get a CMOR checker."""
+    var_info = get_var_info(project, mip, short_name)
+
+    def _checker(cube: Cube) -> CMORCheck:
         return CMORCheck(cube,
                          var_info,
                          frequency=frequency,
@@ -1105,105 +867,143 @@ def _get_cmor_checker(table,
     return _checker
 
 
-def cmor_check_metadata(cube,
-                        cmor_table,
-                        mip,
-                        short_name,
-                        frequency,
-                        check_level=CheckLevels.DEFAULT):
+def cmor_check_metadata(
+    cube: Cube,
+    cmor_table: str,
+    mip: str,
+    short_name: str,
+    frequency: Optional[str] = None,
+    check_level: CheckLevels = CheckLevels.DEFAULT,
+) -> Cube:
     """Check if metadata conforms to variable's CMOR definition.
 
     None of the checks at this step will force the cube to load the data.
 
     Parameters
     ----------
-    cube: iris.cube.Cube
+    cube:
         Data cube to check.
-    cmor_table: str
-        CMOR definitions to use.
+    cmor_table:
+        CMOR definitions to use (i.e., the variable's project).
     mip:
-        Variable's mip.
-    short_name: str
+        Variable's MIP.
+    short_name:
         Variable's short name.
-    frequency: str
-        Data frequency.
-    check_level: CheckLevels
+    frequency:
+        Data frequency. If not given, use the one from the CMOR table of the
+        variable.
+    check_level:
         Level of strictness of the checks.
+
+    Returns
+    -------
+    iris.cube.Cube
+        Checked cube.
+
     """
-    checker = _get_cmor_checker(cmor_table,
-                                mip,
-                                short_name,
-                                frequency,
-                                check_level=check_level)
-    checker(cube).check_metadata()
+    checker = _get_cmor_checker(
+        cmor_table,
+        mip,
+        short_name,
+        frequency=frequency,
+        check_level=check_level,
+    )
+    cube = checker(cube).check_metadata()
     return cube
 
 
-def cmor_check_data(cube,
-                    cmor_table,
-                    mip,
-                    short_name,
-                    frequency,
-                    check_level=CheckLevels.DEFAULT):
+def cmor_check_data(
+    cube: Cube,
+    cmor_table: str,
+    mip: str,
+    short_name: str,
+    frequency: Optional[str] = None,
+    check_level: CheckLevels = CheckLevels.DEFAULT,
+) -> Cube:
     """Check if data conforms to variable's CMOR definition.
 
-    The checks performed at this step require the data in memory.
-
     Parameters
     ----------
-    cube: iris.cube.Cube
+    cube:
         Data cube to check.
-    cmor_table: str
-        CMOR definitions to use.
+    cmor_table:
+        CMOR definitions to use (i.e., the variable's project).
     mip:
-        Variable's mip.
-    short_name: str
+        Variable's MIP.
+    short_name:
         Variable's short name
-    frequency: str
-        Data frequency
-    check_level: CheckLevels
+    frequency:
+        Data frequency. If not given, use the one from the CMOR table of the
+        variable.
+    check_level:
         Level of strictness of the checks.
+
+    Returns
+    -------
+    iris.cube.Cube
+        Checked cube.
+
     """
-    checker = _get_cmor_checker(cmor_table,
-                                mip,
-                                short_name,
-                                frequency,
-                                check_level=check_level)
-    checker(cube).check_data()
+    checker = _get_cmor_checker(
+        cmor_table,
+        mip,
+        short_name,
+        frequency=frequency,
+        check_level=check_level,
+    )
+    cube = checker(cube).check_data()
     return cube
 
 
-def cmor_check(cube, cmor_table, mip, short_name, frequency, check_level):
+def cmor_check(
+    cube: Cube,
+    cmor_table: str,
+    mip: str,
+    short_name: str,
+    frequency: Optional[str] = None,
+    check_level: CheckLevels = CheckLevels.DEFAULT,
+) -> Cube:
     """Check if cube conforms to variable's CMOR definition.
 
-    Equivalent to calling cmor_check_metadata and cmor_check_data
-    consecutively.
+    Equivalent to calling :func:`cmor_check_metadata` and
+    :func:`cmor_check_data` consecutively.
 
     Parameters
     ----------
-    cube: iris.cube.Cube
+    cube:
         Data cube to check.
-    cmor_table: str
-        CMOR definitions to use.
+    cmor_table:
+        CMOR definitions to use (i.e., the variable's project).
     mip:
-        Variable's mip.
-    short_name: str
+        Variable's MIP.
+    short_name:
         Variable's short name.
-    frequency: str
-        Data frequency.
-    check_level: enum.IntEnum
+    frequency:
+        Data frequency. If not given, use the one from the CMOR table of the
+        variable.
+    check_level:
         Level of strictness of the checks.
+
+    Returns
+    -------
+    iris.cube.Cube
+        Checked cube.
+
     """
-    cmor_check_metadata(cube,
-                        cmor_table,
-                        mip,
-                        short_name,
-                        frequency,
-                        check_level=check_level)
-    cmor_check_data(cube,
-                    cmor_table,
-                    mip,
-                    short_name,
-                    frequency,
-                    check_level=check_level)
+    cube = cmor_check_metadata(
+        cube,
+        cmor_table,
+        mip,
+        short_name,
+        frequency=frequency,
+        check_level=check_level,
+    )
+    cube = cmor_check_data(
+        cube,
+        cmor_table,
+        mip,
+        short_name,
+        frequency=frequency,
+        check_level=check_level,
+    )
     return cube
diff --git a/esmvalcore/cmor/fix.py b/esmvalcore/cmor/fix.py
index 1034435f9..d05af5ef6 100644
--- a/esmvalcore/cmor/fix.py
+++ b/esmvalcore/cmor/fix.py
@@ -7,14 +7,17 @@ variables to be sure that all known errors are fixed.
 from __future__ import annotations
 
 import logging
+import warnings
 from collections import defaultdict
+from collections.abc import Sequence
 from pathlib import Path
 from typing import TYPE_CHECKING, Optional
 
-from iris.cube import CubeList
+from iris.cube import Cube, CubeList
 
-from ._fixes.fix import Fix
-from .check import CheckLevels, _get_cmor_checker
+from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor.check import CheckLevels, _get_cmor_checker
+from esmvalcore.exceptions import ESMValCoreDeprecationWarning
 
 if TYPE_CHECKING:
     from ..config import Session
@@ -31,11 +34,12 @@ def fix_file(
     output_dir: Path,
     add_unique_suffix: bool = False,
     session: Optional[Session] = None,
+    frequency: Optional[str] = None,
     **extra_facets,
 ) -> str | Path:
     """Fix files before ESMValTool can load them.
 
-    This fixes are only for issues that prevent iris from loading the cube or
+    These fixes are only for issues that prevent iris from loading the cube or
     that cannot be fixed after the cube is loaded.
 
     Original files are not overwritten.
@@ -58,6 +62,8 @@ def fix_file(
         Adds a unique suffix to `output_dir` for thread safety.
     session:
         Current session which includes configuration and directory information.
+    frequency:
+        Variable's data frequency, if available.
     **extra_facets:
         Extra facets are mainly used for data outside of the big projects like
         CMIP, CORDEX, obs4MIPs. For details, see :ref:`extra_facets`.
@@ -75,6 +81,7 @@ def fix_file(
         'project': project,
         'dataset': dataset,
         'mip': mip,
+        'frequency': frequency,
     })
 
     for fix in Fix.get_fixes(project=project,
@@ -82,61 +89,81 @@ def fix_file(
                              mip=mip,
                              short_name=short_name,
                              extra_facets=extra_facets,
-                             session=session):
+                             session=session,
+                             frequency=frequency):
         file = fix.fix_file(
             file, output_dir, add_unique_suffix=add_unique_suffix
         )
     return file
 
 
-def fix_metadata(cubes,
-                 short_name,
-                 project,
-                 dataset,
-                 mip,
-                 frequency=None,
-                 check_level=CheckLevels.DEFAULT,
-                 session: Optional[Session] = None,
-                 **extra_facets):
-    """Fix cube metadata if fixes are required and check it anyway.
+def fix_metadata(
+    cubes: Sequence[Cube],
+    short_name: str,
+    project: str,
+    dataset: str,
+    mip: str,
+    frequency: Optional[str] = None,
+    check_level: CheckLevels = CheckLevels.DEFAULT,
+    session: Optional[Session] = None,
+    **extra_facets,
+) -> CubeList:
+    """Fix cube metadata if fixes are required.
 
-    This method collects all the relevant fixes for a given variable, applies
-    them and checks the resulting cube (or the original if no fixes were
-    needed) metadata to ensure that it complies with the standards of its
-    project CMOR tables.
+    This method collects all the relevant fixes (including generic ones) for a
+    given variable and applies them.
 
     Parameters
     ----------
-    cubes: iris.cube.CubeList
+    cubes:
         Cubes to fix.
-    short_name: str
+    short_name:
         Variable's short name.
-    project: str
+    project:
         Project of the dataset.
-    dataset: str
+    dataset:
         Name of the dataset.
-    mip: str
+    mip:
         Variable's MIP.
-    frequency: str, optional
+    frequency:
         Variable's data frequency, if available.
-    check_level: CheckLevels
-        Level of strictness of the checks. Set to default.
-    session: Session, optional
+    check_level:
+        Level of strictness of the checks.
+
+        .. deprecated:: 2.10.0
+            This option has been deprecated in ESMValCore version 2.10.0 and is
+            scheduled for removal in version 2.12.0. Please use the functions
+            :func:`~esmvalcore.preprocessor.cmor_check_metadata`,
+            :func:`~esmvalcore.preprocessor.cmor_check_data`, or
+            :meth:`~esmvalcore.cmor.check.cmor_check` instead. This function
+            will no longer perform CMOR checks. Fixes and CMOR checks have been
+            clearly separated in ESMValCore version 2.10.0.
+    session:
         Current session which includes configuration and directory information.
-    **extra_facets: dict, optional
+    **extra_facets:
         Extra facets are mainly used for data outside of the big projects like
         CMIP, CORDEX, obs4MIPs. For details, see :ref:`extra_facets`.
 
     Returns
     -------
-    iris.cube.Cube:
-        Fixed and checked cube.
+    iris.cube.CubeList
+        Fixed cubes.
 
-    Raises
-    ------
-    CMORCheckError
-        If the checker detects errors in the metadata that it can not fix.
     """
+    # Deprecate CMOR checks (remove in v2.12)
+    if check_level != CheckLevels.DEFAULT:
+        msg = (
+            "The option `check_level` has been deprecated in ESMValCore "
+            "version 2.10.0 and is scheduled for removal in version 2.12.0. "
+            "Please use the functions "
+            "esmvalcore.preprocessor.cmor_check_metadata, "
+            "esmvalcore.preprocessor.cmor_check_data, or "
+            "esmvalcore.cmor.check.cmor_check instead. This function will no "
+            "longer perform CMOR checks. Fixes and CMOR checks have been "
+            "clearly separated in ESMValCore version 2.10.0."
+        )
+        warnings.warn(msg, ESMValCoreDeprecationWarning)
+
     # Update extra_facets with variable information given as regular arguments
     # to this function
     extra_facets.update({
@@ -152,8 +179,12 @@ def fix_metadata(cubes,
                           mip=mip,
                           short_name=short_name,
                           extra_facets=extra_facets,
-                          session=session)
-    fixed_cubes = []
+                          session=session,
+                          frequency=frequency)
+    fixed_cubes = CubeList()
+
+    # Group cubes by input file and apply all fixes to each group element
+    # (i.e., each file) individually
     by_file = defaultdict(list)
     for cube in cubes:
         by_file[cube.attributes.get('source_file', '')].append(cube)
@@ -163,94 +194,97 @@ def fix_metadata(cubes,
         for fix in fixes:
             cube_list = fix.fix_metadata(cube_list)
 
-        cube = _get_single_cube(cube_list, short_name, project, dataset)
-        checker = _get_cmor_checker(frequency=frequency,
-                                    table=project,
-                                    mip=mip,
-                                    short_name=short_name,
-                                    check_level=check_level,
-                                    fail_on_error=False,
-                                    automatic_fixes=True)
+        # The final fix is always GenericFix, whose fix_metadata method always
+        # returns a single cube
+        cube = cube_list[0]
+
+        # Perform CMOR checks
+        # TODO: remove in v2.12
+        checker = _get_cmor_checker(
+            project,
+            mip,
+            short_name,
+            frequency,
+            fail_on_error=False,
+            check_level=check_level,
+        )
         cube = checker(cube).check_metadata()
+
         cube.attributes.pop('source_file', None)
         fixed_cubes.append(cube)
-    return fixed_cubes
 
-
-def _get_single_cube(cube_list, short_name, project, dataset):
-    if len(cube_list) == 1:
-        return cube_list[0]
-    cube = None
-    for raw_cube in cube_list:
-        if raw_cube.var_name == short_name:
-            cube = raw_cube
-            break
-    if not cube:
-        raise ValueError(
-            f'More than one cube found for variable {short_name} in '
-            f'{project}:{dataset} but none of their var_names match the '
-            f'expected.\nFull list of cubes encountered: {cube_list}'
-        )
-    logger.warning(
-        'Found variable %s in %s:%s, but there were other present in '
-        'the file. Those extra variables are usually metadata '
-        '(cell area, latitude descriptions) that was not saved '
-        'according to CF-conventions. It is possible that errors appear '
-        'further on because of this. \nFull list of cubes encountered: %s',
-        short_name, project, dataset, cube_list)
-    return cube
+    return fixed_cubes
 
 
-def fix_data(cube,
-             short_name,
-             project,
-             dataset,
-             mip,
-             frequency=None,
-             check_level=CheckLevels.DEFAULT,
-             session: Optional[Session] = None,
-             **extra_facets):
-    """Fix cube data if fixes add present and check it anyway.
+def fix_data(
+    cube: Cube,
+    short_name: str,
+    project: str,
+    dataset: str,
+    mip: str,
+    frequency: Optional[str] = None,
+    check_level: CheckLevels = CheckLevels.DEFAULT,
+    session: Optional[Session] = None,
+    **extra_facets,
+) -> Cube:
+    """Fix cube data if fixes are required.
 
     This method assumes that metadata is already fixed and checked.
 
-    This method collects all the relevant fixes for a given variable, applies
-    them and checks resulting cube (or the original if no fixes were
-    needed) metadata to ensure that it complies with the standards of its
-    project CMOR tables.
+    This method collects all the relevant fixes (including generic ones) for a
+    given variable and applies them.
 
     Parameters
     ----------
-    cube: iris.cube.Cube
+    cube:
         Cube to fix.
-    short_name: str
+    short_name:
         Variable's short name.
-    project: str
+    project:
         Project of the dataset.
-    dataset: str
+    dataset:
         Name of the dataset.
-    mip: str
+    mip:
         Variable's MIP.
-    frequency: str, optional
+    frequency:
         Variable's data frequency, if available.
-    check_level: CheckLevels
-        Level of strictness of the checks. Set to default.
-    session: Session, optional
+    check_level:
+        Level of strictness of the checks.
+
+        .. deprecated:: 2.10.0
+            This option has been deprecated in ESMValCore version 2.10.0 and is
+            scheduled for removal in version 2.12.0. Please use the functions
+            :func:`~esmvalcore.preprocessor.cmor_check_metadata`,
+            :func:`~esmvalcore.preprocessor.cmor_check_data`, or
+            :meth:`~esmvalcore.cmor.check.cmor_check` instead. This function
+            will no longer perform CMOR checks. Fixes and CMOR checks have been
+            clearly separated in ESMValCore version 2.10.0.
+    session:
         Current session which includes configuration and directory information.
-    **extra_facets: dict, optional
+    **extra_facets:
         Extra facets are mainly used for data outside of the big projects like
         CMIP, CORDEX, obs4MIPs. For details, see :ref:`extra_facets`.
 
     Returns
     -------
-    iris.cube.Cube:
-        Fixed and checked cube.
+    iris.cube.Cube
+        Fixed cube.
 
-    Raises
-    ------
-    CMORCheckError
-        If the checker detects errors in the data that it can not fix.
     """
+    # Deprecate CMOR checks (remove in v2.12)
+    if check_level != CheckLevels.DEFAULT:
+        msg = (
+            "The option `check_level` has been deprecated in ESMValCore "
+            "version 2.10.0 and is scheduled for removal in version 2.12.0. "
+            "Please use the functions "
+            "esmvalcore.preprocessor.cmor_check_metadata, "
+            "esmvalcore.preprocessor.cmor_check_data, or "
+            "esmvalcore.cmor.check.cmor_check instead. This function will no "
+            "longer perform CMOR checks. Fixes and CMOR checks have been "
+            "clearly separated in ESMValCore version 2.10.0."
+        )
+        warnings.warn(msg, ESMValCoreDeprecationWarning)
+
     # Update extra_facets with variable information given as regular arguments
     # to this function
     extra_facets.update({
@@ -266,14 +300,20 @@ def fix_data(cube,
                              mip=mip,
                              short_name=short_name,
                              extra_facets=extra_facets,
-                             session=session):
+                             session=session,
+                             frequency=frequency):
         cube = fix.fix_data(cube)
-    checker = _get_cmor_checker(frequency=frequency,
-                                table=project,
-                                mip=mip,
-                                short_name=short_name,
-                                fail_on_error=False,
-                                automatic_fixes=True,
-                                check_level=check_level)
+
+    # Perform CMOR checks
+    # TODO: remove in v2.12
+    checker = _get_cmor_checker(
+        project,
+        mip,
+        short_name,
+        frequency,
+        fail_on_error=False,
+        check_level=check_level,
+    )
     cube = checker(cube).check_data()
+
     return cube
diff --git a/esmvalcore/cmor/table.py b/esmvalcore/cmor/table.py
index 680e7289a..01659aa20 100644
--- a/esmvalcore/cmor/table.py
+++ b/esmvalcore/cmor/table.py
@@ -11,8 +11,6 @@ import glob
 import json
 import logging
 import os
-import tempfile
-import warnings
 from collections import Counter
 from functools import lru_cache, total_ordering
 from pathlib import Path
@@ -20,7 +18,7 @@ from typing import Optional, Union
 
 import yaml
 
-from esmvalcore.exceptions import ESMValCoreDeprecationWarning, RecipeError
+from esmvalcore.exceptions import RecipeError
 
 logger = logging.getLogger(__name__)
 
@@ -72,18 +70,50 @@ def _get_mips(project: str, short_name: str) -> list[str]:
     return mips
 
 
-def get_var_info(project, mip, short_name):
+def get_var_info(
+    project: str,
+    mip: str,
+    short_name: str,
+) -> VariableInfo | None:
     """Get variable information.
 
+    Note
+    ----
+    If `project=CORDEX` and the `mip` ends with 'hr', it is cropped to 'h'
+    since CORDEX X-hourly tables define the `mip` as ending in 'h' instead of
+    'hr'.
+
     Parameters
     ----------
-    project : str
+    project:
         Dataset's project.
-    mip : str
-        Variable's cmor table.
-    short_name : str
+    mip:
+        Variable's CMOR table, i.e., MIP.
+    short_name:
         Variable's short name.
+
+    Returns
+    -------
+    VariableInfo | None
+        `VariableInfo` object for the requested variable if found, ``None``
+        otherwise.
+
+    Raises
+    ------
+    KeyError
+        No CMOR tables available for `project`.
+
     """
+    if project not in CMOR_TABLES:
+        raise KeyError(
+            f"No CMOR tables available for project '{project}'. The following "
+            f"tables are available: {', '.join(CMOR_TABLES)}."
+        )
+
+    # CORDEX X-hourly tables define the mip as ending in 'h' instead of 'hr'
+    if project == 'CORDEX' and mip.endswith('hr'):
+        mip = mip.replace('hr', 'h')
+
     return CMOR_TABLES[project].get_variable(mip, short_name)
 
 
@@ -94,35 +124,11 @@ def read_cmor_tables(cfg_developer: Optional[Path] = None) -> None:
     ----------
     cfg_developer:
         Path to config-developer.yml file.
-
-        Prior to v2.8.0 `cfg_developer` was an :obj:`dict` with the contents
-        of config-developer.yml. This is deprecated and support will be
-        removed in v2.10.0.
     """
-    if isinstance(cfg_developer, dict):
-        warnings.warn(
-            "Using the `read_cmor_tables` file with a dictionary as argument "
-            "has been deprecated in ESMValCore version 2.8.0 and is "
-            "scheduled for removal in version 2.10.0. "
-            "Please use the path to the config-developer.yml file instead.",
-            ESMValCoreDeprecationWarning,
-        )
-        with tempfile.NamedTemporaryFile(
-            mode='w',
-            encoding='utf-8',
-            delete=False,
-        ) as file:
-            yaml.safe_dump(cfg_developer, file)
-            cfg_file = Path(file.name)
-    else:
-        cfg_file = cfg_developer
-    if cfg_file is None:
-        cfg_file = Path(__file__).parents[1] / 'config-developer.yml'
-    mtime = cfg_file.stat().st_mtime
-    cmor_tables = _read_cmor_tables(cfg_file, mtime)
-    if isinstance(cfg_developer, dict):
-        # clean up the temporary file
-        cfg_file.unlink()
+    if cfg_developer is None:
+        cfg_developer = Path(__file__).parents[1] / 'config-developer.yml'
+    mtime = cfg_developer.stat().st_mtime
+    cmor_tables = _read_cmor_tables(cfg_developer, mtime)
     CMOR_TABLES.clear()
     CMOR_TABLES.update(cmor_tables)
 
@@ -219,6 +225,7 @@ class InfoBase():
         If False, will look for a variable in other tables if it can not be
         found in the requested one
     """
+
     def __init__(self, default, alt_names, strict):
         if alt_names is None:
             alt_names = ""
@@ -243,28 +250,35 @@ class InfoBase():
         """
         return self.tables.get(table)
 
-    def get_variable(self, table_name, short_name, derived=False):
-        """Search and return the variable info.
+    def get_variable(
+        self,
+        table_name: str,
+        short_name: str,
+        derived: Optional[bool] = False,
+    ) -> VariableInfo | None:
+        """Search and return the variable information.
 
         Parameters
         ----------
-        table_name: str
-            Table name
-        short_name: str
-            Variable's short name
-        derived: bool, optional
-            Variable is derived. Info retrieval for derived variables always
-            look on the default tables if variable is not find in the
-            requested table
+        table_name:
+            Table name, i.e., the variable's MIP.
+        short_name:
+            Variable's short name.
+        derived:
+            Variable is derived. Information retrieval for derived variables
+            always looks in the default tables (usually, the custom tables) if
+            variable is not found in the requested table.
 
         Returns
         -------
-        VariableInfo
-            Return the VariableInfo object for the requested variable if
-            found, returns None if not
+        VariableInfo | None
+            `VariableInfo` object for the requested variable if found, ``None``
+            otherwise.
+
         """
         alt_names_list = self._get_alt_names_list(short_name)
 
+        # First, look in requested table
         table = self.get_table(table_name)
         if table:
             for alt_names in alt_names_list:
@@ -273,10 +287,19 @@ class InfoBase():
                 except KeyError:
                     pass
 
+        # If that didn't work, look in all tables (i.e., other MIPs) if
+        # cmor_strict=False
         var_info = self._look_in_all_tables(alt_names_list)
+
+        # If that didn' work either, look in default table if cmor_strict=False
+        # or derived=True
         if not var_info:
             var_info = self._look_in_default(derived, alt_names_list,
                                              table_name)
+
+        # If necessary, adapt frequency of variable (set it to the one from the
+        # requested MIP). E.g., if the user asked for table `Amon`, but the
+        # variable has been found in `day`, use frequency `mon`.
         if var_info:
             var_info = var_info.copy()
             var_info = self._update_frequency_from_mip(table_name, var_info)
@@ -284,6 +307,7 @@ class InfoBase():
         return var_info
 
     def _look_in_default(self, derived, alt_names_list, table_name):
+        """Look for variable in default table."""
         var_info = None
         if (not self.strict or derived):
             for alt_names in alt_names_list:
@@ -293,6 +317,7 @@ class InfoBase():
         return var_info
 
     def _look_in_all_tables(self, alt_names_list):
+        """Look for variable in all tables."""
         var_info = None
         if not self.strict:
             for alt_names in alt_names_list:
@@ -302,6 +327,7 @@ class InfoBase():
         return var_info
 
     def _get_alt_names_list(self, short_name):
+        """Get list of alternative variable names."""
         alt_names_list = [short_name]
         for alt_names in self.alt_names:
             if short_name in alt_names:
@@ -312,12 +338,14 @@ class InfoBase():
         return alt_names_list
 
     def _update_frequency_from_mip(self, table_name, var_info):
+        """Update frequency information of var_info from table."""
         mip_info = self.get_table(table_name)
         if mip_info:
             var_info.frequency = mip_info.frequency
         return var_info
 
     def _look_all_tables(self, alt_names):
+        """Look for variable in all tables."""
         for table_vars in sorted(self.tables.values()):
             if alt_names in table_vars:
                 return table_vars[alt_names]
@@ -341,6 +369,7 @@ class CMIP6Info(InfoBase):
         If False, will look for a variable in other tables if it can not be
         found in the requested one
     """
+
     def __init__(self,
                  cmor_tables_path,
                  default=None,
@@ -497,6 +526,7 @@ class CMIP6Info(InfoBase):
 @total_ordering
 class TableInfo(dict):
     """Container class for storing a CMOR table."""
+
     def __init__(self, *args, **kwargs):
         """Create a new TableInfo object for storing VariableInfo objects."""
         super(TableInfo, self).__init__(*args, **kwargs)
@@ -522,6 +552,7 @@ class JsonInfo(object):
 
     Provides common utility methods to read json variables
     """
+
     def __init__(self):
         self._json_data = {}
 
@@ -562,6 +593,7 @@ class JsonInfo(object):
 
 class VariableInfo(JsonInfo):
     """Class to read and store variable information."""
+
     def __init__(self, table_type, short_name):
         """Class to read and store variable information.
 
@@ -673,6 +705,7 @@ class VariableInfo(JsonInfo):
 
 class CoordinateInfo(JsonInfo):
     """Class to read and store coordinate information."""
+
     def __init__(self, name):
         """Class to read and store coordinate information.
 
@@ -760,6 +793,7 @@ class CMIP5Info(InfoBase):
         If False, will look for a variable in other tables if it can not be
         found in the requested one
     """
+
     def __init__(self,
                  cmor_tables_path,
                  default=None,
@@ -918,6 +952,7 @@ class CMIP3Info(CMIP5Info):
         If False, will look for a variable in other tables if it can not be
         found in the requested one
     """
+
     def _read_table_file(self, table_file, table=None):
         for dim in ('zlevel', ):
             coord = CoordinateInfo(dim)
diff --git a/esmvalcore/dataset.py b/esmvalcore/dataset.py
index 35c858840..849a9a579 100644
--- a/esmvalcore/dataset.py
+++ b/esmvalcore/dataset.py
@@ -677,19 +677,15 @@ class Dataset:
         iris.cube.Cube
             An :mod:`iris` cube with the data corresponding the the dataset.
         """
-        return self._load_with_callback(callback='default')
-
-    def _load_with_callback(self, callback):
-        # TODO: Remove the callback argument for v2.10.0.
         input_files = list(self.files)
         for supplementary_dataset in self.supplementaries:
             input_files.extend(supplementary_dataset.files)
         esgf.download(input_files, self.session['download_dir'])
 
-        cube = self._load(callback)
+        cube = self._load()
         supplementary_cubes = []
         for supplementary_dataset in self.supplementaries:
-            supplementary_cube = supplementary_dataset._load(callback)
+            supplementary_cube = supplementary_dataset._load()
             supplementary_cubes.append(supplementary_cube)
 
         output_file = _get_output_file(self.facets, self.session.preproc_dir)
@@ -704,7 +700,7 @@ class Dataset:
 
         return cubes[0]
 
-    def _load(self, callback) -> Cube:
+    def _load(self) -> Cube:
         """Load self.files into an iris cube and return it."""
         if not self.files:
             lines = [
@@ -731,7 +727,6 @@ class Dataset:
             **self.facets,
         }
         settings['load'] = {
-            'callback': callback,
             'ignore_warnings': get_ignored_warnings(
                 self.facets['project'], 'load'
             ),
diff --git a/esmvalcore/preprocessor/__init__.py b/esmvalcore/preprocessor/__init__.py
index 736ed0215..36d8cc495 100644
--- a/esmvalcore/preprocessor/__init__.py
+++ b/esmvalcore/preprocessor/__init__.py
@@ -371,6 +371,10 @@ def preprocess(
     function = globals()[step]
     itype = _get_itype(step)
 
+    for item in items:
+        if isinstance(item, Cube) and item.has_lazy_data():
+            item.data = item.core_data().rechunk()
+
     result = []
     if itype.endswith('s'):
         result.append(_run_preproc_function(function, items, settings,
@@ -478,10 +482,7 @@ class PreprocessorFile(TrackedFile):
     def cubes(self):
         """Cubes."""
         if self._cubes is None:
-            callback = self.settings.get('load', {}).get('callback')
-            self._cubes = [
-                ds._load_with_callback(callback) for ds in self.datasets
-            ]
+            self._cubes = [ds.load() for ds in self.datasets]
         return self._cubes
 
     @cubes.setter
diff --git a/esmvalcore/preprocessor/_io.py b/esmvalcore/preprocessor/_io.py
index 62eb52853..596b3b331 100644
--- a/esmvalcore/preprocessor/_io.py
+++ b/esmvalcore/preprocessor/_io.py
@@ -6,7 +6,6 @@ import logging
 import os
 import shutil
 import warnings
-from collections.abc import Callable
 from itertools import groupby
 from pathlib import Path
 from typing import Optional
@@ -96,7 +95,7 @@ def _get_attr_from_field_coord(ncfield, coord_name, attr):
     return None
 
 
-def concatenate_callback(raw_cube, field, _):
+def _load_callback(raw_cube, field, _):
     """Use this callback to fix anything Iris tries to break."""
     # Remove attributes that cause issues with merging and concatenation
     _delete_attributes(
@@ -122,7 +121,6 @@ def _delete_attributes(iris_object, atts):
 
 def load(
     file: str | Path,
-    callback: Optional[Callable] = None,
     ignore_warnings: Optional[list[dict]] = None,
 ) -> CubeList:
     """Load iris cubes from string or Path objects.
@@ -131,11 +129,6 @@ def load(
     ----------
     file:
         File to be loaded. Could be string or POSIX Path object.
-    callback:
-        Callback function passed to :func:`iris.load_raw`.
-
-        .. deprecated:: 2.8.0
-            This argument will be removed in 2.10.0.
     ignore_warnings:
         Keyword arguments passed to :func:`warnings.filterwarnings` used to
         ignore warnings issued by :func:`iris.load_raw`. Each list element
@@ -152,14 +145,6 @@ def load(
         Cubes are empty.
 
     """
-    if not (callback is None or callback == 'default'):
-        msg = ("The argument `callback` has been deprecated in "
-               "ESMValCore version 2.8.0 and is scheduled for removal in "
-               "version 2.10.0.")
-        warnings.warn(msg, ESMValCoreDeprecationWarning)
-    if callback == 'default':
-        callback = concatenate_callback
-
     file = Path(file)
     logger.debug("Loading:\n%s", file)
 
@@ -191,7 +176,7 @@ def load(
         # warnings.filterwarnings
         # (see https://github.com/SciTools/cf-units/issues/240)
         with suppress_errors():
-            raw_cubes = iris.load_raw(file, callback=callback)
+            raw_cubes = iris.load_raw(file, callback=_load_callback)
     logger.debug("Done with loading %s", file)
 
     if not raw_cubes:
diff --git a/esmvalcore/preprocessor/_time.py b/esmvalcore/preprocessor/_time.py
index 265004a8c..e49afd478 100644
--- a/esmvalcore/preprocessor/_time.py
+++ b/esmvalcore/preprocessor/_time.py
@@ -22,7 +22,7 @@ from iris.coords import AuxCoord
 from iris.cube import Cube, CubeList
 from iris.time import PartialDateTime
 
-from esmvalcore.cmor.check import _get_next_month, _get_time_bounds
+from esmvalcore.cmor._fixes.fix import get_next_month, get_time_bounds
 from esmvalcore.iris_helpers import date2num
 
 from ._shared import get_iris_analysis_operation, operator_accept_weights
@@ -128,7 +128,7 @@ def _parse_end_date(date):
         if len(date) == 4:
             end_date = datetime.datetime(int(date) + 1, 1, 1, 0, 0, 0)
         elif len(date) == 6:
-            month, year = _get_next_month(int(date[4:]), int(date[0:4]))
+            month, year = get_next_month(int(date[4:]), int(date[0:4]))
             end_date = datetime.datetime(year, month, 1, 0, 0, 0)
         else:
             try:
@@ -966,7 +966,7 @@ def regrid_time(cube: Cube, frequency: str) -> Cube:
 
     # uniformize bounds
     cube.coord('time').bounds = None
-    cube.coord('time').bounds = _get_time_bounds(cube.coord('time'), frequency)
+    cube.coord('time').bounds = get_time_bounds(cube.coord('time'), frequency)
 
     # remove aux coords that will differ
     reset_aux = ['day_of_month', 'day_of_year']


Test patch:
diff --git a/tests/integration/cmor/_fixes/cesm/test_cesm2.py b/tests/integration/cmor/_fixes/cesm/test_cesm2.py
index 44fed835b..661eadcfb 100644
--- a/tests/integration/cmor/_fixes/cesm/test_cesm2.py
+++ b/tests/integration/cmor/_fixes/cesm/test_cesm2.py
@@ -7,6 +7,7 @@ from iris.coords import CellMethod, DimCoord
 from iris.cube import Cube, CubeList
 
 import esmvalcore.cmor._fixes.cesm.cesm2
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import CoordinateInfo, get_var_info
 from esmvalcore.config._config import get_extra_facets
@@ -338,6 +339,7 @@ def test_get_tas_fix():
     fix = Fix.get_fixes('CESM', 'CESM2', 'Amon', 'tas')
     assert fix == [
         esmvalcore.cmor._fixes.cesm.cesm2.AllVars(None),
+        GenericFix(None),
     ]
 
 
diff --git a/tests/integration/cmor/_fixes/cmip5/test_access1_0.py b/tests/integration/cmor/_fixes/cmip5/test_access1_0.py
index 1312762aa..3cba189b7 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_access1_0.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_access1_0.py
@@ -8,7 +8,7 @@ from iris.coords import AuxCoord, DimCoord
 from iris.cube import Cube, CubeList
 
 from esmvalcore.cmor._fixes.cmip5.access1_0 import AllVars, Cl
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 from esmvalcore.cmor.table import get_var_info
 from esmvalcore.iris_helpers import date2num
 
@@ -39,8 +39,9 @@ class TestAllVars:
     @staticmethod
     def test_get():
         """Test getting of fix."""
-        assert (Fix.get_fixes('CMIP5', 'ACCESS1-0', 'Amon', 'tas')
-                == [AllVars(None)])
+        assert Fix.get_fixes('CMIP5', 'ACCESS1-0', 'Amon', 'tas') == [
+            AllVars(None),  GenericFix(None)
+        ]
 
     @staticmethod
     def test_fix_metadata(cube):
@@ -66,7 +67,7 @@ class TestAllVars:
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'ACCESS1-0', 'Amon', 'cl')
-    assert fix == [Cl(None), AllVars(None)]
+    assert fix == [Cl(None), AllVars(None), GenericFix(None)]
 
 
 @pytest.fixture
diff --git a/tests/integration/cmor/_fixes/cmip5/test_access1_3.py b/tests/integration/cmor/_fixes/cmip5/test_access1_3.py
index 68d59201d..684e88f65 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_access1_3.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_access1_3.py
@@ -8,7 +8,7 @@ from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.access1_0 import Cl as BaseCl
 from esmvalcore.cmor._fixes.cmip5.access1_3 import AllVars, Cl
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 from esmvalcore.iris_helpers import date2num
 
 
@@ -38,8 +38,9 @@ class TestAllVars:
     @staticmethod
     def test_get():
         """Test getting of fix."""
-        assert (Fix.get_fixes('CMIP5', 'ACCESS1-3', 'Amon', 'tas')
-                == [AllVars(None)])
+        assert Fix.get_fixes('CMIP5', 'ACCESS1-3', 'Amon', 'tas') == [
+             AllVars(None), GenericFix(None)
+        ]
 
     @staticmethod
     def test_fix_metadata(cube):
@@ -65,7 +66,7 @@ class TestAllVars:
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'ACCESS1-3', 'Amon', 'cl')
-    assert fix == [Cl(None), AllVars(None)]
+    assert fix == [Cl(None), AllVars(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_bcc_csm1_1.py b/tests/integration/cmor/_fixes/cmip5/test_bcc_csm1_1.py
index 48d846146..65f37766e 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_bcc_csm1_1.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_bcc_csm1_1.py
@@ -1,5 +1,4 @@
 """Test bcc-csm1-1 fixes."""
-import unittest
 
 import iris
 import numpy as np
@@ -9,6 +8,7 @@ from esmvalcore.cmor._fixes.common import (
     ClFixHybridPressureCoord,
     OceanFixGrid,
 )
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -16,7 +16,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'bcc-csm1-1', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -24,13 +24,10 @@ def test_cl_fix():
     assert Cl is ClFixHybridPressureCoord
 
 
-class TestTos(unittest.TestCase):
-    """Test tos fixes."""
-
-    def test_get(self):
-        """Test fix get."""
-        self.assertListEqual(
-            Fix.get_fixes('CMIP5', 'bcc-csm1-1', 'Amon', 'tos'), [Tos(None)])
+def test_get_tos_fix():
+    """Test getting of fix."""
+    fix = Fix.get_fixes('CMIP5', 'bcc-csm1-1', 'Omon', 'tos')
+    assert fix == [Tos(None), GenericFix(None)]
 
 
 def test_tos_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_bcc_csm1_1_m.py b/tests/integration/cmor/_fixes/cmip5/test_bcc_csm1_1_m.py
index 8473c84f4..8fe017fe9 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_bcc_csm1_1_m.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_bcc_csm1_1_m.py
@@ -1,18 +1,17 @@
 """Test fixes for bcc-csm1-1-m."""
-import unittest
 
 from esmvalcore.cmor._fixes.cmip5.bcc_csm1_1_m import Cl, Tos
 from esmvalcore.cmor._fixes.common import (
     ClFixHybridPressureCoord,
     OceanFixGrid,
 )
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'bcc-csm1-1-m', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -20,13 +19,10 @@ def test_cl_fix():
     assert Cl is ClFixHybridPressureCoord
 
 
-class TestTos(unittest.TestCase):
-    """Test tos fixes."""
-
-    def test_get(self):
-        """Test fix get."""
-        self.assertListEqual(
-            Fix.get_fixes('CMIP5', 'bcc-csm1-1-m', 'Amon', 'tos'), [Tos(None)])
+def test_get_tos_fix():
+    """Test getting of fix."""
+    fix = Fix.get_fixes('CMIP5', 'bcc-csm1-1-m', 'Omon', 'tos')
+    assert fix == [Tos(None), GenericFix(None)]
 
 
 def test_tos_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_bnu_esm.py b/tests/integration/cmor/_fixes/cmip5/test_bnu_esm.py
index e8045902f..d988e0244 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_bnu_esm.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_bnu_esm.py
@@ -5,9 +5,16 @@ import numpy.ma as ma
 from cf_units import Unit
 from iris.cube import Cube
 
-from esmvalcore.cmor._fixes.cmip5.bnu_esm import (Ch4, Cl, Co2, FgCo2,
-                                                  Od550Aer, SpCo2)
+from esmvalcore.cmor._fixes.cmip5.bnu_esm import (
+    Ch4,
+    Cl,
+    Co2,
+    FgCo2,
+    Od550Aer,
+    SpCo2,
+)
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -22,7 +29,7 @@ class TestCl(unittest.TestCase):
     def test_get(self):
         """Test fix get"""
         fix = Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'cl')
-        assert fix == [Cl(None)]
+        assert fix == [Cl(None), GenericFix(None)]
 
     def test_cl_fix(self):
         """Test fix for ``cl``."""
@@ -46,7 +53,7 @@ class TestCo2(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'co2'),
-                             [Co2(self.vardef)])
+                             [Co2(self.vardef), GenericFix(None)])
 
     def test_fix_metadata(self):
         """Test unit change."""
@@ -74,7 +81,7 @@ class Testfgco2(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'fgco2'),
-            [FgCo2(self.vardef)])
+            [FgCo2(self.vardef), GenericFix(None)])
 
     def test_fix_metadata(self):
         """Test unit fix."""
@@ -101,7 +108,7 @@ class TestCh4(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'ch4'),
-                             [Ch4(self.vardef)])
+                             [Ch4(self.vardef), GenericFix(None)])
 
     def test_fix_metadata(self):
         """Test unit fix."""
@@ -127,7 +134,8 @@ class Testspco2(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(
-            Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'spco2'), [SpCo2(None)])
+            Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'spco2'),
+            [SpCo2(None), GenericFix(None)])
 
     def test_fix_metadata(self):
         """Test fix."""
@@ -157,7 +165,7 @@ class TestOd550Aer(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'od550aer'),
-            [Od550Aer(None)])
+            [Od550Aer(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_canesm2.py b/tests/integration/cmor/_fixes/cmip5/test_canesm2.py
index 27d29839a..4e8f9c826 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_canesm2.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_canesm2.py
@@ -6,13 +6,14 @@ from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.canesm2 import Cl, FgCo2
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'CanESM2', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -31,7 +32,8 @@ class TestCanESM2Fgco2(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(
-            Fix.get_fixes('CMIP5', 'CANESM2', 'Amon', 'fgco2'), [FgCo2(None)])
+            Fix.get_fixes('CMIP5', 'CANESM2', 'Amon', 'fgco2'),
+            [FgCo2(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_ccsm4.py b/tests/integration/cmor/_fixes/cmip5/test_ccsm4.py
index f19cc9816..05bb6620a 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_ccsm4.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_ccsm4.py
@@ -7,6 +7,7 @@ from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.bnu_esm import Cl as BaseCl
 from esmvalcore.cmor._fixes.cmip5.ccsm4 import AllVars, Cl, Csoil, So
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -59,7 +60,7 @@ class TestsAllVars(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'CCSM4', 'Amon', 'rlut'),
-                             [AllVars(None)])
+                             [AllVars(None), GenericFix(None)])
 
     def test_fix_metadata(self):
         """Check that latitudes values are rounded."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_cesm1_bgc.py b/tests/integration/cmor/_fixes/cmip5/test_cesm1_bgc.py
index 31fb3f670..fdb2314d8 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_cesm1_bgc.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_cesm1_bgc.py
@@ -6,13 +6,14 @@ from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.cesm1_bgc import Cl, Gpp, Nbp
 from esmvalcore.cmor._fixes.cmip5.cesm1_cam5 import Cl as BaseCl
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'CESM1-BGC', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -31,7 +32,8 @@ class TestGpp(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(
-            Fix.get_fixes('CMIP5', 'CESM1-BGC', 'Amon', 'gpp'), [Gpp(None)])
+            Fix.get_fixes('CMIP5', 'CESM1-BGC', 'Amon', 'gpp'),
+            [Gpp(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test fix to set missing values correctly."""
@@ -54,4 +56,5 @@ class TestNbp(TestGpp):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(
-            Fix.get_fixes('CMIP5', 'CESM1-BGC', 'Amon', 'nbp'), [Nbp(None)])
+            Fix.get_fixes('CMIP5', 'CESM1-BGC', 'Amon', 'nbp'),
+            [Nbp(None), GenericFix(None)])
diff --git a/tests/integration/cmor/_fixes/cmip5/test_cesm1_cam5.py b/tests/integration/cmor/_fixes/cmip5/test_cesm1_cam5.py
index d5991ddff..07cf8ab1a 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_cesm1_cam5.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_cesm1_cam5.py
@@ -3,13 +3,14 @@ import iris
 import pytest
 
 from esmvalcore.cmor._fixes.cmip5.cesm1_cam5 import Cl
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'CESM1-CAM5', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 @pytest.fixture
diff --git a/tests/integration/cmor/_fixes/cmip5/test_cesm1_fastchem.py b/tests/integration/cmor/_fixes/cmip5/test_cesm1_fastchem.py
index a41d1996f..6ae2a4491 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_cesm1_fastchem.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_cesm1_fastchem.py
@@ -1,13 +1,14 @@
 """Tests for CESM1-FASTCHEM fixes."""
 from esmvalcore.cmor._fixes.cmip5.cesm1_cam5 import Cl as BaseCl
 from esmvalcore.cmor._fixes.cmip5.cesm1_fastchem import Cl
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'CESM1-FASTCHEM', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_cesm1_waccm.py b/tests/integration/cmor/_fixes/cmip5/test_cesm1_waccm.py
index 20023eebf..146a456da 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_cesm1_waccm.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_cesm1_waccm.py
@@ -1,13 +1,14 @@
 """Tests for CESM1-WACCM fixes."""
 from esmvalcore.cmor._fixes.cmip5.cesm1_cam5 import Cl as BaseCl
 from esmvalcore.cmor._fixes.cmip5.cesm1_waccm import Cl
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'CESM1-WACCM', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_cnrm_cm5.py b/tests/integration/cmor/_fixes/cmip5/test_cnrm_cm5.py
index ae9da2ef0..ce6ebe012 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_cnrm_cm5.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_cnrm_cm5.py
@@ -4,8 +4,9 @@ import unittest
 from cf_units import Unit
 from iris.cube import Cube
 
-from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor._fixes.cmip5.cnrm_cm5 import Msftmyz, Msftmyzba
+from esmvalcore.cmor._fixes.fix import GenericFix
+from esmvalcore.cmor.fix import Fix
 
 
 class TestMsftmyz(unittest.TestCase):
@@ -19,7 +20,7 @@ class TestMsftmyz(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'CNRM-CM5', 'Amon', 'msftmyz'),
-            [Msftmyz(None)])
+            [Msftmyz(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -39,7 +40,7 @@ class TestMsftmyzba(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'CNRM-CM5', 'Amon', 'msftmyzba'),
-            [Msftmyzba(None)])
+            [Msftmyzba(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_csiro_mk3_6_0.py b/tests/integration/cmor/_fixes/cmip5/test_csiro_mk3_6_0.py
index a7d23d9d4..3fa4318d7 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_csiro_mk3_6_0.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_csiro_mk3_6_0.py
@@ -1,13 +1,13 @@
 """Test fixes for CSIRO-Mk3-6-0."""
 from esmvalcore.cmor._fixes.cmip5.csiro_mk3_6_0 import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'CSIRO-Mk3-6-0', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_ec_earth.py b/tests/integration/cmor/_fixes/cmip5/test_ec_earth.py
index 8ec734a90..4b480ef81 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_ec_earth.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_ec_earth.py
@@ -2,18 +2,19 @@
 import unittest
 
 import numpy as np
-
 from cf_units import Unit
 from iris.coords import AuxCoord, DimCoord
 from iris.cube import Cube, CubeList
 from iris.exceptions import CoordinateNotFoundError
+
 from esmvalcore.cmor._fixes.cmip5.ec_earth import (
     Areacello,
     Pr,
     Sftlf,
     Sic,
     Tas,
-    )
+)
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -27,7 +28,7 @@ class TestSic(unittest.TestCase):
     def test_get(self):
         """Test fix get"""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'EC-EARTH', 'Amon', 'sic'),
-                             [Sic(None)])
+                             [Sic(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -46,7 +47,8 @@ class TestSftlf(unittest.TestCase):
     def test_get(self):
         """Test fix get"""
         self.assertListEqual(
-            Fix.get_fixes('CMIP5', 'EC-EARTH', 'Amon', 'sftlf'), [Sftlf(None)])
+            Fix.get_fixes('CMIP5', 'EC-EARTH', 'Amon', 'sftlf'),
+            [Sftlf(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -90,7 +92,7 @@ class TestTas(unittest.TestCase):
     def test_get(self):
         """Test fix get"""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'EC-EARTH', 'Amon', 'tas'),
-                             [Tas(None)])
+                             [Tas(None), GenericFix(None)])
 
     def test_tas_fix_metadata(self):
         """Test metadata fix."""
@@ -148,7 +150,7 @@ class TestAreacello(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'EC-EARTH', 'Omon', 'areacello'),
-            [Areacello(None)],
+            [Areacello(None), GenericFix(None)],
         )
 
     def test_areacello_fix_metadata(self):
@@ -210,7 +212,7 @@ class TestPr(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'EC-EARTH', 'Amon', 'pr'),
-            [Pr(None)],
+            [Pr(None), GenericFix(None)],
         )
 
     def test_pr_fix_metadata(self):
diff --git a/tests/integration/cmor/_fixes/cmip5/test_fgoals_g2.py b/tests/integration/cmor/_fixes/cmip5/test_fgoals_g2.py
index abda3d180..b70b16fa2 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_fgoals_g2.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_fgoals_g2.py
@@ -5,6 +5,7 @@ from iris.coords import DimCoord
 from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.fgoals_g2 import AllVars
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -33,8 +34,9 @@ class TestAll:
     @staticmethod
     def test_get():
         """Test fix get."""
-        assert (Fix.get_fixes('CMIP5', 'FGOALS-G2', 'Amon', 'tas')
-                == [AllVars(None)])
+        assert Fix.get_fixes('CMIP5', 'FGOALS-G2', 'Amon', 'tas') == [
+             AllVars(None), GenericFix(None)
+        ]
 
     @staticmethod
     def test_fix_metadata(cube):
diff --git a/tests/integration/cmor/_fixes/cmip5/test_fgoals_s2.py b/tests/integration/cmor/_fixes/cmip5/test_fgoals_s2.py
index e77c095b3..a1c15afeb 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_fgoals_s2.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_fgoals_s2.py
@@ -4,13 +4,14 @@ from iris.coords import AuxCoord, DimCoord
 from iris.cube import Cube, CubeList
 
 from esmvalcore.cmor._fixes.cmip5.fgoals_s2 import AllVars
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_allvars_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'FGOALS-s2', 'Amon', 'tas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 LAT_COORD = DimCoord(
diff --git a/tests/integration/cmor/_fixes/cmip5/test_fio_esm.py b/tests/integration/cmor/_fixes/cmip5/test_fio_esm.py
index b8b8429f3..c0705e58f 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_fio_esm.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_fio_esm.py
@@ -4,15 +4,16 @@ import unittest
 from cf_units import Unit
 from iris.cube import Cube
 
-from esmvalcore.cmor.fix import Fix
-from esmvalcore.cmor._fixes.cmip5.fio_esm import Ch4, Cl, Co2
 from esmvalcore.cmor._fixes.cmip5.cesm1_cam5 import Cl as BaseCl
+from esmvalcore.cmor._fixes.cmip5.fio_esm import Ch4, Cl, Co2
+from esmvalcore.cmor._fixes.fix import GenericFix
+from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'FIO-ESM', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -30,7 +31,7 @@ class TestCh4(unittest.TestCase):
     def test_get(self):
         """Test fix get"""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'FIO-ESM', 'Amon', 'ch4'),
-                             [Ch4(None)])
+                             [Ch4(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -49,7 +50,7 @@ class TestCo2(unittest.TestCase):
     def test_get(self):
         """Test fix get"""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'FIO-ESM', 'Amon', 'co2'),
-                             [Co2(None)])
+                             [Co2(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_gfdl_cm2p1.py b/tests/integration/cmor/_fixes/cmip5/test_gfdl_cm2p1.py
index 63d5ce426..8a4fa19fd 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_gfdl_cm2p1.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_gfdl_cm2p1.py
@@ -6,9 +6,15 @@ import iris
 from cf_units import Unit
 from iris.cube import Cube
 
-from esmvalcore.cmor._fixes.cmip5.gfdl_cm2p1 import (AllVars, Areacello, Cl,
-                                                     Sftof, Sit)
 from esmvalcore.cmor._fixes.cmip5.cesm1_cam5 import Cl as BaseCl
+from esmvalcore.cmor._fixes.cmip5.gfdl_cm2p1 import (
+    AllVars,
+    Areacello,
+    Cl,
+    Sftof,
+    Sit,
+)
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -19,7 +25,7 @@ class TestCl(unittest.TestCase):
         """Test getting of fix."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-CM2P1', 'Amon', 'cl'),
-            [Cl(None), AllVars(None)])
+            [Cl(None), AllVars(None), GenericFix(None)])
 
     def test_fix(self):
         """Test fix for ``cl``."""
@@ -37,7 +43,7 @@ class TestSftof(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-CM2P1', 'fx', 'sftof'),
-            [Sftof(None), AllVars(None)])
+            [Sftof(None), AllVars(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -59,7 +65,9 @@ class TestAreacello(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-CM2P1', 'Amon', 'areacello'),
-            [Areacello(self.vardef), AllVars(self.vardef)])
+            [Areacello(self.vardef),
+             AllVars(self.vardef),
+             GenericFix(self.vardef)])
 
     def test_fix_metadata(self):
         """Test data fix."""
@@ -101,7 +109,7 @@ class TestSit(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-CM2P1', 'OImon', 'sit'),
-            [Sit(self.var_info_mock), AllVars(None)])
+            [Sit(self.var_info_mock), AllVars(None), GenericFix(None)])
 
     def test_fix_metadata_day_do_nothing(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_gfdl_cm3.py b/tests/integration/cmor/_fixes/cmip5/test_gfdl_cm3.py
index c4aaae272..bcda26c95 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_gfdl_cm3.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_gfdl_cm3.py
@@ -5,6 +5,7 @@ from cf_units import Unit
 from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.gfdl_cm3 import AllVars, Areacello, Sftof
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -20,7 +21,7 @@ class TestSftof(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-CM3', 'fx', 'sftof'),
-            [Sftof(None), AllVars(None)])
+            [Sftof(None), AllVars(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -41,7 +42,9 @@ class TestAreacello(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-CM3', 'Amon', 'areacello'),
-            [Areacello(self.vardef), AllVars(self.vardef)])
+            [Areacello(self.vardef),
+             AllVars(self.vardef),
+             GenericFix(self.vardef)])
 
     def test_fix_metadata(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_gfdl_esm2g.py b/tests/integration/cmor/_fixes/cmip5/test_gfdl_esm2g.py
index 89a1a1e32..d5189e84c 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_gfdl_esm2g.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_gfdl_esm2g.py
@@ -7,9 +7,16 @@ import pytest
 from cf_units import Unit
 from iris.cube import Cube
 
-from esmvalcore.cmor._fixes.cmip5.gfdl_esm2g import (AllVars, Areacello, Co2,
-                                                     FgCo2, Usi, Vsi,
-                                                     _get_and_remove)
+from esmvalcore.cmor._fixes.cmip5.gfdl_esm2g import (
+    AllVars,
+    Areacello,
+    Co2,
+    FgCo2,
+    Usi,
+    Vsi,
+    _get_and_remove,
+)
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -71,7 +78,7 @@ class TestCo2(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-ESM2G', 'Amon', 'co2'),
-            [Co2(None), AllVars(None)])
+            [Co2(None), AllVars(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -92,7 +99,9 @@ class TestUsi(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-ESM2G', 'day', 'usi'),
-            [Usi(self.vardef), AllVars(self.vardef)])
+            [Usi(self.vardef),
+             AllVars(self.vardef),
+             GenericFix(self.vardef)])
 
     def test_fix_data(self):
         """Test metadata fix."""
@@ -112,7 +121,9 @@ class TestVsi(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-ESM2G', 'day', 'vsi'),
-            [Vsi(self.vardef), AllVars(self.vardef)])
+            [Vsi(self.vardef),
+             AllVars(self.vardef),
+             GenericFix(self.vardef)])
 
     def test_fix_data(self):
         """Test metadata fix."""
@@ -132,7 +143,9 @@ class TestAreacello(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-ESM2G', 'fx', 'areacello'),
-            [Areacello(self.vardef), AllVars(self.vardef)])
+            [Areacello(self.vardef),
+             AllVars(self.vardef),
+             GenericFix(self.vardef)])
 
     def test_fix_metadata(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_gfdl_esm2m.py b/tests/integration/cmor/_fixes/cmip5/test_gfdl_esm2m.py
index 1538098d2..1897ba5c8 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_gfdl_esm2m.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_gfdl_esm2m.py
@@ -4,8 +4,13 @@ import unittest
 from cf_units import Unit
 from iris.cube import Cube
 
-from esmvalcore.cmor._fixes.cmip5.gfdl_esm2m import (AllVars, Areacello, Co2,
-                                                     Sftof)
+from esmvalcore.cmor._fixes.cmip5.gfdl_esm2m import (
+    AllVars,
+    Areacello,
+    Co2,
+    Sftof,
+)
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -21,7 +26,7 @@ class TestSftof(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-ESM2M', 'fx', 'sftof'),
-            [Sftof(None), AllVars(None)])
+            [Sftof(None), AllVars(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -41,7 +46,7 @@ class TestCo2(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-ESM2M', 'Amon', 'co2'),
-            [Co2(None), AllVars(None)])
+            [Co2(None), AllVars(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -62,7 +67,9 @@ class TestAreacello(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'GFDL-ESM2M', 'fx', 'areacello'),
-            [Areacello(self.vardef), AllVars(self.vardef)])
+            [Areacello(self.vardef),
+             AllVars(self.vardef),
+             GenericFix(self.vardef)])
 
     def test_fix_metadata(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_giss_e2_h.py b/tests/integration/cmor/_fixes/cmip5/test_giss_e2_h.py
index 5fd78f648..9c39dd136 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_giss_e2_h.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_giss_e2_h.py
@@ -1,13 +1,13 @@
 """Test fixes for GISS-E2-H."""
 from esmvalcore.cmor._fixes.cmip5.giss_e2_h import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'GISS-E2-H', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_giss_e2_r.py b/tests/integration/cmor/_fixes/cmip5/test_giss_e2_r.py
index e030bb4aa..d95b517cd 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_giss_e2_r.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_giss_e2_r.py
@@ -1,13 +1,13 @@
 """Test fixes for GISS-E2-R."""
 from esmvalcore.cmor._fixes.cmip5.giss_e2_r import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'GISS-E2-R', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_hadgem2_cc.py b/tests/integration/cmor/_fixes/cmip5/test_hadgem2_cc.py
index ed2f7c0d1..0e6a4fc57 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_hadgem2_cc.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_hadgem2_cc.py
@@ -1,8 +1,9 @@
 """Test HADGEM2-CC fixes."""
 import unittest
 
+from esmvalcore.cmor._fixes.cmip5.hadgem2_cc import O2, AllVars
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
-from esmvalcore.cmor._fixes.cmip5.hadgem2_cc import AllVars, O2
 
 
 class TestAllVars(unittest.TestCase):
@@ -11,7 +12,7 @@ class TestAllVars(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'HADGEM2-CC', 'Amon', 'tas'),
-            [AllVars(None)])
+            [AllVars(None), GenericFix(None)])
 
 
 class TestO2(unittest.TestCase):
@@ -20,4 +21,4 @@ class TestO2(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'HADGEM2-CC', 'Amon', 'o2'),
-            [O2(None), AllVars(None)])
+            [O2(None), AllVars(None), GenericFix(None)])
diff --git a/tests/integration/cmor/_fixes/cmip5/test_hadgem2_es.py b/tests/integration/cmor/_fixes/cmip5/test_hadgem2_es.py
index 99c7eb4aa..c0ab2bb8f 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_hadgem2_es.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_hadgem2_es.py
@@ -3,6 +3,7 @@ import unittest
 
 from esmvalcore.cmor._fixes.cmip5.hadgem2_es import O2, AllVars, Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridHeightCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -13,7 +14,7 @@ class TestAllVars(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'HADGEM2-ES', 'Amon', 'tas'),
-            [AllVars(None)])
+            [AllVars(None), GenericFix(None)])
 
 
 class TestO2(unittest.TestCase):
@@ -23,13 +24,13 @@ class TestO2(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'HADGEM2-ES', 'Amon', 'o2'),
-            [O2(None), AllVars(None)])
+            [O2(None), AllVars(None), GenericFix(None)])
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'HadGEM2-ES', 'Amon', 'cl')
-    assert fix == [Cl(None), AllVars(None)]
+    assert fix == [Cl(None), AllVars(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_inmcm4.py b/tests/integration/cmor/_fixes/cmip5/test_inmcm4.py
index a5a5cf023..dcabbbf31 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_inmcm4.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_inmcm4.py
@@ -6,13 +6,14 @@ from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.inmcm4 import Cl, Gpp, Lai, Nbp
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'inmcm4', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -31,7 +32,7 @@ class TestGpp(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'INMCM4', 'Amon', 'gpp'),
-                             [Gpp(None)])
+                             [Gpp(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fox."""
@@ -51,7 +52,7 @@ class TestLai(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'INMCM4', 'Amon', 'lai'),
-                             [Lai(None)])
+                             [Lai(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -71,7 +72,7 @@ class TestNbp(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'INMCM4', 'Amon', 'nbp'),
-                             [Nbp(None)])
+                             [Nbp(None), GenericFix(None)])
 
     def test_fix_metadata(self):
         """Test fix on nbp files to set standard_name."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5a_lr.py b/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5a_lr.py
index 443a4aafb..67f50c1ea 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5a_lr.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5a_lr.py
@@ -1,13 +1,13 @@
 """Test fixes for IPSL-CM5A-LR."""
 from esmvalcore.cmor._fixes.cmip5.ipsl_cm5a_lr import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'IPSL-CM5A-LR', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5a_mr.py b/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5a_mr.py
index ff3e0adc2..787a2d804 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5a_mr.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5a_mr.py
@@ -1,13 +1,13 @@
 """Test fixes for IPSL-CM5A-MR."""
 from esmvalcore.cmor._fixes.cmip5.ipsl_cm5a_mr import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'IPSL-CM5A-MR', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5b_lr.py b/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5b_lr.py
index e04fa4718..4a7b0a447 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5b_lr.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_ipsl_cm5b_lr.py
@@ -1,13 +1,13 @@
 """Test fixes for IPSL-CM5B-LR."""
 from esmvalcore.cmor._fixes.cmip5.ipsl_cm5b_lr import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'IPSL-CM5B-LR', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_miroc5.py b/tests/integration/cmor/_fixes/cmip5/test_miroc5.py
index a9d61dde1..63a706eef 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_miroc5.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_miroc5.py
@@ -7,13 +7,14 @@ from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.miroc5 import Cl, Hur, Pr, Sftof, Tas
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'MIROC5', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -24,13 +25,13 @@ def test_cl_fix():
 def test_get_hur_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'MIROC5', 'Amon', 'hur')
-    assert fix == [Hur(None)]
+    assert fix == [Hur(None), GenericFix(None)]
 
 
 def test_get_pr_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'MIROC5', 'Amon', 'pr')
-    assert fix == [Pr(None)]
+    assert fix == [Pr(None), GenericFix(None)]
 
 
 @unittest.mock.patch(
@@ -64,7 +65,7 @@ class TestSftof(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'MIROC5', 'Amon', 'sftof'),
-                             [Sftof(None)])
+                             [Sftof(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -88,7 +89,7 @@ class TestTas(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('CMIP5', 'MIROC5', 'Amon', 'tas'),
-                             [Tas(None)])
+                             [Tas(None), GenericFix(None)])
 
     def test_fix_metadata(self):
         """Test metadata fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_miroc_esm.py b/tests/integration/cmor/_fixes/cmip5/test_miroc_esm.py
index f87902a8d..1010e4e67 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_miroc_esm.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_miroc_esm.py
@@ -9,6 +9,7 @@ from iris.exceptions import CoordinateNotFoundError
 
 from esmvalcore.cmor._fixes.cmip5.miroc_esm import AllVars, Cl, Co2, Tro3
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -16,7 +17,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'MIROC-ESM', 'Amon', 'cl')
-    assert fix == [Cl(None), AllVars(None)]
+    assert fix == [Cl(None), AllVars(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -37,7 +38,9 @@ class TestCo2(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'MIROC-ESM', 'Amon', 'co2'),
-            [Co2(self.vardef), AllVars(self.vardef)])
+            [Co2(self.vardef),
+             AllVars(self.vardef),
+             GenericFix(self.vardef)])
 
     def test_fix_metadata(self):
         """Test unit fix."""
@@ -58,7 +61,7 @@ class TestTro3(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'MIROC-ESM', 'Amon', 'tro3'),
-            [Tro3(None), AllVars(None)])
+            [Tro3(None), AllVars(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -102,7 +105,7 @@ class TestAll(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'MIROC-ESM', 'Amon', 'tos'),
-            [AllVars(None)])
+            [AllVars(None), GenericFix(None)])
 
     def test_fix_metadata_plev(self):
         """Test plev fix."""
@@ -112,7 +115,7 @@ class TestAll(unittest.TestCase):
         cube.coord('air_pressure')
 
     def test_fix_metadata_no_plev(self):
-        """Test plev fix wotk with no plev."""
+        """Test plev fix work with no plev."""
         self.cube.remove_coord('AR5PL35')
         cube = self.fix.fix_metadata([self.cube])[0]
         with self.assertRaises(CoordinateNotFoundError):
diff --git a/tests/integration/cmor/_fixes/cmip5/test_miroc_esm_chem.py b/tests/integration/cmor/_fixes/cmip5/test_miroc_esm_chem.py
index 186f32171..1e14dfd30 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_miroc_esm_chem.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_miroc_esm_chem.py
@@ -5,8 +5,9 @@ import unittest
 from cf_units import Unit
 from iris.cube import Cube
 
-from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor._fixes.cmip5.miroc_esm_chem import Tro3
+from esmvalcore.cmor._fixes.fix import GenericFix
+from esmvalcore.cmor.fix import Fix
 
 
 class TestTro3(unittest.TestCase):
@@ -20,7 +21,7 @@ class TestTro3(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'MIROC-ESM-CHEM', 'Amon', 'tro3'),
-            [Tro3(None)])
+            [Tro3(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_lr.py b/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_lr.py
index effb781f9..07aa974d1 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_lr.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_lr.py
@@ -6,13 +6,14 @@ from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip5.mpi_esm_lr import Cl, Pctisccp
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'MPI-ESM-LR', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -32,7 +33,7 @@ class TestPctisccp2(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'MPI-ESM-LR', 'Amon', 'pctisccp'),
-            [Pctisccp(None)])
+            [Pctisccp(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
diff --git a/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_mr.py b/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_mr.py
index 1c074d41a..96cd83b96 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_mr.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_mr.py
@@ -1,13 +1,13 @@
 """Test fixes for MPI-ESM-MR."""
 from esmvalcore.cmor._fixes.cmip5.mpi_esm_mr import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'MPI-ESM-MR', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_p.py b/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_p.py
index 7e0aa87a5..2466e5a9f 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_p.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_mpi_esm_p.py
@@ -1,13 +1,13 @@
 """Test fixes for MPI-ESM-P."""
 from esmvalcore.cmor._fixes.cmip5.mpi_esm_p import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'MPI-ESM-P', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_mri_cgcm3.py b/tests/integration/cmor/_fixes/cmip5/test_mri_cgcm3.py
index 2b0d85ab7..717c66cee 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_mri_cgcm3.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_mri_cgcm3.py
@@ -3,13 +3,14 @@ import unittest
 
 from esmvalcore.cmor._fixes.cmip5.mri_cgcm3 import Cl, Msftmyz, ThetaO
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'MRI-CGCM3', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -24,7 +25,7 @@ class TestMsftmyz(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'MRI-CGCM3', 'Amon', 'msftmyz'),
-            [Msftmyz(None)])
+            [Msftmyz(None), GenericFix(None)])
 
 
 class TestThetao(unittest.TestCase):
@@ -34,4 +35,4 @@ class TestThetao(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'MRI-CGCM3', 'Amon', 'thetao'),
-            [ThetaO(None)])
+            [ThetaO(None), GenericFix(None)])
diff --git a/tests/integration/cmor/_fixes/cmip5/test_mri_esm1.py b/tests/integration/cmor/_fixes/cmip5/test_mri_esm1.py
index c00af1d6f..f4d39eb70 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_mri_esm1.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_mri_esm1.py
@@ -1,8 +1,9 @@
 """Test MRI-ESM1 fixes."""
 import unittest
 
-from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor._fixes.cmip5.mri_esm1 import Msftmyz
+from esmvalcore.cmor._fixes.fix import GenericFix
+from esmvalcore.cmor.fix import Fix
 
 
 class TestMsftmyz(unittest.TestCase):
@@ -11,4 +12,4 @@ class TestMsftmyz(unittest.TestCase):
         """Test fix get"""
         self.assertListEqual(
             Fix.get_fixes('CMIP5', 'MRI-ESM1', 'Amon', 'msftmyz'),
-            [Msftmyz(None)])
+            [Msftmyz(None), GenericFix(None)])
diff --git a/tests/integration/cmor/_fixes/cmip5/test_noresm1_m.py b/tests/integration/cmor/_fixes/cmip5/test_noresm1_m.py
index 79664ce6b..1ad165c63 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_noresm1_m.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_noresm1_m.py
@@ -1,13 +1,13 @@
 """Test fixes for NorESM1-M."""
 from esmvalcore.cmor._fixes.cmip5.noresm1_m import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP5', 'NorESM1-M', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip5/test_noresm1_me.py b/tests/integration/cmor/_fixes/cmip5/test_noresm1_me.py
index ab286d78b..b600311d5 100644
--- a/tests/integration/cmor/_fixes/cmip5/test_noresm1_me.py
+++ b/tests/integration/cmor/_fixes/cmip5/test_noresm1_me.py
@@ -1,10 +1,11 @@
 """Tests for fixes of NorESM1-ME (CMIP5)."""
-import pytest
 import iris
+import pytest
 from iris.cube import CubeList
 
-from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor._fixes.cmip5.noresm1_me import Tas
+from esmvalcore.cmor._fixes.fix import GenericFix
+from esmvalcore.cmor.fix import Fix
 
 DIM_COORD_SHORT = iris.coords.DimCoord(
     [1.0, 2.0, 3.0],
@@ -69,4 +70,6 @@ def test_tas(cubes_in, cubes_out):
 
 def test_get():
     """Test fix get"""
-    assert Fix.get_fixes('CMIP5', 'NORESM1-ME', 'Amon', 'tas') == [Tas(None)]
+    assert Fix.get_fixes('CMIP5', 'NORESM1-ME', 'Amon', 'tas') == [
+        Tas(None), GenericFix(None)
+    ]
diff --git a/tests/integration/cmor/_fixes/cmip6/test_access_cm2.py b/tests/integration/cmor/_fixes/cmip6/test_access_cm2.py
index 0e5bd66eb..00977403e 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_access_cm2.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_access_cm2.py
@@ -7,6 +7,7 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.access_cm2 import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridHeightCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 B_POINTS = [
@@ -108,7 +109,7 @@ def cl_cubes():
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ACCESS-CM2', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -132,7 +133,7 @@ def test_cl_fix_metadata(mock_base_fix_metadata, cl_cubes):
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ACCESS-CM2', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -143,7 +144,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ACCESS-CM2', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_access_esm1_5.py b/tests/integration/cmor/_fixes/cmip6/test_access_esm1_5.py
index d126d3a74..29fb72c87 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_access_esm1_5.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_access_esm1_5.py
@@ -7,6 +7,7 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.access_esm1_5 import Cl, Cli, Clw, Hus, Zg
 from esmvalcore.cmor._fixes.common import ClFixHybridHeightCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -77,7 +78,7 @@ def cl_cubes():
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ACCESS-ESM1-5', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 @unittest.mock.patch(
@@ -101,7 +102,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ACCESS-ESM1-5', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -112,7 +113,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ACCESS-ESM1-5', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -143,7 +144,7 @@ def cubes_with_wrong_air_pressure():
 def test_get_hus_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ACCESS-ESM1-5', 'Amon', 'hus')
-    assert fix == [Hus(None)]
+    assert fix == [Hus(None), GenericFix(None)]
 
 
 def test_hus_fix_metadata(cubes_with_wrong_air_pressure):
@@ -169,7 +170,7 @@ def test_hus_fix_metadata(cubes_with_wrong_air_pressure):
 def test_get_zg_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ACCESS-ESM1-5', 'Amon', 'zg')
-    assert fix == [Zg(None)]
+    assert fix == [Zg(None), GenericFix(None)]
 
 
 def test_zg_fix_metadata(cubes_with_wrong_air_pressure):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_awi_cm_1_1_mr.py b/tests/integration/cmor/_fixes/cmip6/test_awi_cm_1_1_mr.py
index f198e2f69..780b09bd7 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_awi_cm_1_1_mr.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_awi_cm_1_1_mr.py
@@ -3,6 +3,7 @@ import iris
 import pytest
 
 from esmvalcore.cmor._fixes.cmip6.awi_cm_1_1_mr import AllVars
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -34,7 +35,7 @@ def cubes():
 
 def test_get_allvars_fix():
     fix = Fix.get_fixes('CMIP6', 'AWI-CM-1-1-MR', 'Amon', 'wrong_lat_lname')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_metadata(cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_awi_esm_1_1_lr.py b/tests/integration/cmor/_fixes/cmip6/test_awi_esm_1_1_lr.py
index eba75631e..07dd1f41e 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_awi_esm_1_1_lr.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_awi_esm_1_1_lr.py
@@ -3,6 +3,7 @@ import iris
 import pytest
 
 from esmvalcore.cmor._fixes.cmip6.awi_esm_1_1_lr import AllVars
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -15,7 +16,7 @@ def sample_cubes():
 
 def test_get_tas_fix():
     fix = Fix.get_fixes('CMIP6', 'AWI-ESM-1-1-LR', 'Amon', 'tas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_metadata(sample_cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_bcc_csm2_mr.py b/tests/integration/cmor/_fixes/cmip6/test_bcc_csm2_mr.py
index ee5739380..5281953fa 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_bcc_csm2_mr.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_bcc_csm2_mr.py
@@ -12,13 +12,13 @@ from esmvalcore.cmor._fixes.common import (
     ClFixHybridPressureCoord,
     OceanFixGrid,
 )
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_areacello_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'Amon', 'areacello')
-    assert fix == [Areacello(None)]
+    assert fix == [Areacello(None), GenericFix(None)]
 
 
 def test_areacello_fix():
@@ -29,7 +29,7 @@ def test_areacello_fix():
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -40,7 +40,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -51,7 +51,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -62,7 +62,7 @@ def test_clw_fix():
 def test_get_tos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'Omon', 'tos')
-    assert fix == [Tos(None)]
+    assert fix == [Tos(None), GenericFix(None)]
 
 
 def test_tos_fix():
@@ -73,7 +73,7 @@ def test_tos_fix():
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
@@ -84,7 +84,7 @@ def test_siconc_fix():
 def test_get_sos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'Omon', 'sos')
-    assert fix == [Sos(None)]
+    assert fix == [Sos(None), GenericFix(None)]
 
 
 def test_sos_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_bcc_esm1.py b/tests/integration/cmor/_fixes/cmip6/test_bcc_esm1.py
index 382d0268f..076390e92 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_bcc_esm1.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_bcc_esm1.py
@@ -11,13 +11,13 @@ from esmvalcore.cmor._fixes.common import (
     ClFixHybridPressureCoord,
     OceanFixGrid,
 )
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-ESM1', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -28,7 +28,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-ESM1', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -39,7 +39,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-ESM1', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -50,7 +50,7 @@ def test_clw_fix():
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-ESM1', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
@@ -61,7 +61,7 @@ def test_siconc_fix():
 def test_get_sos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-ESM1', 'Omon', 'sos')
-    assert fix == [Sos(None)]
+    assert fix == [Sos(None), GenericFix(None)]
 
 
 def test_sos_fix():
@@ -72,7 +72,7 @@ def test_sos_fix():
 def test_get_tos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-ESM1', 'Omon', 'tos')
-    assert fix == [Tos(None)]
+    assert fix == [Tos(None), GenericFix(None)]
 
 
 def test_tos_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cams_csm1_0.py b/tests/integration/cmor/_fixes/cmip6/test_cams_csm1_0.py
index 55cb512ae..eb2367539 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cams_csm1_0.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cams_csm1_0.py
@@ -1,13 +1,13 @@
 """Test fixes for CAMS-CSM1-0."""
 from esmvalcore.cmor._fixes.cmip6.cams_csm1_0 import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CAMS-CSM1-0', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +18,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CAMS-CSM1-0', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +29,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CAMS-CSM1-0', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_canesm5.py b/tests/integration/cmor/_fixes/cmip6/test_canesm5.py
index 9b9638e5f..5f23af82f 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_canesm5.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_canesm5.py
@@ -4,13 +4,14 @@ import numpy as np
 import pytest
 
 from esmvalcore.cmor._fixes.cmip6.canesm5 import Co2, Gpp
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_co2_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CanESM5', 'Amon', 'co2')
-    assert fix == [Co2(None)]
+    assert fix == [Co2(None), GenericFix(None)]
 
 
 @pytest.fixture
@@ -48,7 +49,7 @@ def gpp_cube():
 def test_get_gpp_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CanESM5', 'Lmon', 'gpp')
-    assert fix == [Gpp(None)]
+    assert fix == [Gpp(None), GenericFix(None)]
 
 
 def test_gpp_fix_data(gpp_cube):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_canesm5_canoe.py b/tests/integration/cmor/_fixes/cmip6/test_canesm5_canoe.py
index 349444559..f0f43fd59 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_canesm5_canoe.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_canesm5_canoe.py
@@ -2,13 +2,13 @@
 from esmvalcore.cmor._fixes.cmip6.canesm5 import Co2 as BaseCo2
 from esmvalcore.cmor._fixes.cmip6.canesm5 import Gpp as BaseGpp
 from esmvalcore.cmor._fixes.cmip6.canesm5_canoe import Co2, Gpp
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_co2_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CanESM5-CanOE', 'Amon', 'co2')
-    assert fix == [Co2(None)]
+    assert fix == [Co2(None), GenericFix(None)]
 
 
 def test_co2_fix():
@@ -19,7 +19,7 @@ def test_co2_fix():
 def test_get_gpp_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CanESM5-CanOE', 'Lmon', 'gpp')
-    assert fix == [Gpp(None)]
+    assert fix == [Gpp(None), GenericFix(None)]
 
 
 def test_gpp_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cas_esm2_0.py b/tests/integration/cmor/_fixes/cmip6/test_cas_esm2_0.py
index bd018b3f2..2e22f91c1 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cas_esm2_0.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cas_esm2_0.py
@@ -1,13 +1,14 @@
 """Tests for the fixes of CAS-ESM2-0."""
 from esmvalcore.cmor._fixes.cmip6.cas_esm2_0 import Cl
 from esmvalcore.cmor._fixes.cmip6.ciesm import Cl as BaseCl
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CAS-ESM2-0', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cesm2.py b/tests/integration/cmor/_fixes/cmip6/test_cesm2.py
index 55442a323..e60e1727b 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cesm2.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cesm2.py
@@ -19,6 +19,7 @@ from esmvalcore.cmor._fixes.cmip6.cesm2 import (
     Tos,
 )
 from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -26,7 +27,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 AIR_PRESSURE_POINTS = np.array([[[[1.0, 1.0, 1.0, 1.0],
@@ -163,7 +164,7 @@ def test_cl_fix_metadata(cl_cubes):
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -174,7 +175,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -268,31 +269,31 @@ def thetao_cubes():
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2', 'Amon', 'tas')
-    assert fix == [Tas(None)]
+    assert fix == [Tas(None), GenericFix(None)]
 
 
 def test_get_tos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2', 'Omon', 'tos')
-    assert fix == [Tos(None), Omon(None)]
+    assert fix == [Tos(None), Omon(None), GenericFix(None)]
 
 
 def test_get_thetao_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2', 'Omon', 'thetao')
-    assert fix == [Omon(None)]
+    assert fix == [Omon(None), GenericFix(None)]
 
 
 def test_get_fgco2_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2', 'Omon', 'fgco2')
-    assert fix == [Fgco2(None), Omon(None)]
+    assert fix == [Fgco2(None), Omon(None), GenericFix(None)]
 
 
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_tas_fix_metadata(tas_cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cesm2_fv2.py b/tests/integration/cmor/_fixes/cmip6/test_cesm2_fv2.py
index 96a201307..16d8a9c0b 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cesm2_fv2.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cesm2_fv2.py
@@ -12,13 +12,14 @@ from esmvalcore.cmor._fixes.cmip6.cesm2_fv2 import (
     Tas,
 )
 from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-FV2', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -29,7 +30,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-FV2', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -40,7 +41,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-FV2', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -51,7 +52,7 @@ def test_clw_fix():
 def test_get_fgco2_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-FV2', 'Omon', 'fgco2')
-    assert fix == [Fgco2(None), Omon(None)]
+    assert fix == [Fgco2(None), Omon(None), GenericFix(None)]
 
 
 def test_fgco2_fix():
@@ -62,7 +63,7 @@ def test_fgco2_fix():
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-FV2', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
@@ -73,7 +74,7 @@ def test_siconc_fix():
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-FV2', 'Amon', 'tas')
-    assert fix == [Tas(None)]
+    assert fix == [Tas(None), GenericFix(None)]
 
 
 def test_tas_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm.py b/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm.py
index b9075b671..b80beb45f 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm.py
@@ -20,13 +20,14 @@ from esmvalcore.cmor._fixes.cmip6.cesm2_waccm import (
     Tas,
 )
 from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -65,7 +66,7 @@ def test_cl_fix_file(mock_get_filepath, tmp_path, test_data_path):
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -76,7 +77,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -87,7 +88,7 @@ def test_clw_fix():
 def test_get_fgco2_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM', 'Omon', 'fgco2')
-    assert fix == [Fgco2(None), Omon(None)]
+    assert fix == [Fgco2(None), Omon(None), GenericFix(None)]
 
 
 def test_fgco2_fix():
@@ -98,7 +99,7 @@ def test_fgco2_fix():
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
@@ -117,7 +118,7 @@ def tas_cubes():
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM', 'Amon', 'tas')
-    assert fix == [Tas(None)]
+    assert fix == [Tas(None), GenericFix(None)]
 
 
 def test_tas_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm_fv2.py b/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm_fv2.py
index a5ac8f673..d4eb9b4b6 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm_fv2.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm_fv2.py
@@ -1,6 +1,6 @@
 """Tests for the fixes of CESM2-WACCM-FV2."""
-from esmvalcore.cmor._fixes.cmip6.cesm2 import Tas as BaseTas
 from esmvalcore.cmor._fixes.cmip6.cesm2 import Fgco2 as BaseFgco2
+from esmvalcore.cmor._fixes.cmip6.cesm2 import Tas as BaseTas
 from esmvalcore.cmor._fixes.cmip6.cesm2_waccm import Cl as BaseCl
 from esmvalcore.cmor._fixes.cmip6.cesm2_waccm_fv2 import (
     Cl,
@@ -12,13 +12,14 @@ from esmvalcore.cmor._fixes.cmip6.cesm2_waccm_fv2 import (
     Tas,
 )
 from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM-FV2', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -29,7 +30,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM-FV2', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -40,7 +41,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM-FV2', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -51,7 +52,7 @@ def test_clw_fix():
 def test_get_fgco2_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM-FV2', 'Omon', 'fgco2')
-    assert fix == [Fgco2(None), Omon(None)]
+    assert fix == [Fgco2(None), Omon(None), GenericFix(None)]
 
 
 def test_fgco2_fix():
@@ -62,7 +63,7 @@ def test_fgco2_fix():
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM-FV2', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
@@ -73,7 +74,7 @@ def test_siconc_fix():
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CESM2-WACCM-FV2', 'Amon', 'tas')
-    assert fix == [Tas(None)]
+    assert fix == [Tas(None), GenericFix(None)]
 
 
 def test_tas_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_ciesm.py b/tests/integration/cmor/_fixes/cmip6/test_ciesm.py
index 29da65c02..1cf1aa3aa 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_ciesm.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_ciesm.py
@@ -4,13 +4,14 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.ciesm import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CIESM', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 @pytest.fixture
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cmcc_cm2_sr5.py b/tests/integration/cmor/_fixes/cmip6/test_cmcc_cm2_sr5.py
index 44f410427..27aa30628 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cmcc_cm2_sr5.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cmcc_cm2_sr5.py
@@ -6,6 +6,7 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.cmcc_cm2_sr5 import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -13,7 +14,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CMCC-CM2-SR5', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 @pytest.fixture
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cnrm_cm6_1.py b/tests/integration/cmor/_fixes/cmip6/test_cnrm_cm6_1.py
index 8322b1e7f..18ca8a3fa 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cnrm_cm6_1.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cnrm_cm6_1.py
@@ -4,8 +4,14 @@ import iris
 import numpy as np
 import pytest
 
-from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import (Cl, Clcalipso,
-                                                     Cli, Clw, Omon)
+from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import (
+    Cl,
+    Clcalipso,
+    Cli,
+    Clw,
+    Omon,
+)
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -14,7 +20,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-CM6-1', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 AIR_PRESSURE_POINTS = np.array([[[[1.0, 1.0],
@@ -85,7 +91,7 @@ def test_cl_fix_metadata(test_data_path):
 def test_get_clcalipso_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-CM6-1', 'CFmon', 'clcalipso')
-    assert fix == [Clcalipso(None)]
+    assert fix == [Clcalipso(None), GenericFix(None)]
 
 
 @pytest.fixture
@@ -113,7 +119,7 @@ def test_clcalipso_fix_metadata(clcalipso_cubes):
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-CM6-1', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -124,7 +130,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-CM6-1', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -135,4 +141,4 @@ def test_clw_fix():
 def test_get_thetao_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-CM6-1', 'Omon', 'thetao')
-    assert fix == [Omon(None)]
+    assert fix == [Omon(None), GenericFix(None)]
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cnrm_cm6_1_hr.py b/tests/integration/cmor/_fixes/cmip6/test_cnrm_cm6_1_hr.py
index fa43c06ac..9ac3e8bad 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cnrm_cm6_1_hr.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cnrm_cm6_1_hr.py
@@ -3,13 +3,13 @@ from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import Cl as BaseCl
 from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import Cli as BaseCli
 from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import Clw as BaseClw
 from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1_hr import Cl, Cli, Clw
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-CM6-1-HR', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -20,7 +20,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-CM6-1-HR', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -31,7 +31,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-CM6-1-HR', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_cnrm_esm2_1.py b/tests/integration/cmor/_fixes/cmip6/test_cnrm_esm2_1.py
index 8ff7b7e0a..3e6d66ebb 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_cnrm_esm2_1.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_cnrm_esm2_1.py
@@ -7,16 +7,21 @@ from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import Cl as BaseCl
 from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import Clcalipso as BaseClcalipso
 from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import Cli as BaseCli
 from esmvalcore.cmor._fixes.cmip6.cnrm_cm6_1 import Clw as BaseClw
-from esmvalcore.cmor._fixes.cmip6.cnrm_esm2_1 import (Cl, Clcalipso,
-                                                      Cli, Clw, Omon)
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.cmip6.cnrm_esm2_1 import (
+    Cl,
+    Clcalipso,
+    Cli,
+    Clw,
+    Omon,
+)
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 from esmvalcore.cmor.table import get_var_info
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-ESM2-1', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -27,7 +32,7 @@ def test_cl_fix():
 def test_get_clcalipso_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-ESM2-1', 'Amon', 'clcalipso')
-    assert fix == [Clcalipso(None)]
+    assert fix == [Clcalipso(None), GenericFix(None)]
 
 
 def test_clcalipso_fix():
@@ -38,7 +43,7 @@ def test_clcalipso_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-ESM2-1', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -49,7 +54,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-ESM2-1', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -88,7 +93,7 @@ def thetao_cubes():
 def test_get_thetao_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'CNRM-ESM2-1', 'Omon', 'thetao')
-    assert fix == [Omon(None)]
+    assert fix == [Omon(None), GenericFix(None)]
 
 
 def test_thetao_fix_metadata(thetao_cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_e3sm_1_0.py b/tests/integration/cmor/_fixes/cmip6/test_e3sm_1_0.py
index e86de9e3a..890c81fd6 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_e3sm_1_0.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_e3sm_1_0.py
@@ -1,13 +1,14 @@
 """Tests for the fixes of E3SM-1-0."""
 from esmvalcore.cmor._fixes.cmip6.e3sm_1_0 import Cl
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'E3SM-1-0', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_ec_earth3_veg.py b/tests/integration/cmor/_fixes/cmip6/test_ec_earth3_veg.py
index f30904b46..b9145e6e8 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_ec_earth3_veg.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_ec_earth3_veg.py
@@ -14,6 +14,7 @@ from esmvalcore.cmor._fixes.cmip6.ec_earth3_veg import (
     Siconca,
     Tas,
 )
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -30,7 +31,7 @@ class TestSiconca(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('CMIP6', 'EC-Earth3-Veg', 'SImon', 'siconca'),
-            [Siconca(None)])
+            [Siconca(None), GenericFix(None)])
 
     def test_fix_data(self):
         """Test data fix."""
@@ -41,13 +42,13 @@ class TestSiconca(unittest.TestCase):
 
 def test_get_siconc_fix():
     """Test sinconc calendar is fixed."""
-    fix, = Fix.get_fixes('CMIP6', 'EC-Earth3-Veg', 'SImon', 'siconc')
+    fix = Fix.get_fixes('CMIP6', 'EC-Earth3-Veg', 'SImon', 'siconc')[0]
     assert isinstance(fix, CalendarFix)
 
 
 def test_get_tos_fix():
     """Test tos calendar is fixed."""
-    fix, = Fix.get_fixes('CMIP6', 'EC-Earth3-Veg', 'Omon', 'tos')
+    fix = Fix.get_fixes('CMIP6', 'EC-Earth3-Veg', 'Omon', 'tos')[0]
     assert isinstance(fix, CalendarFix)
 
 
@@ -110,7 +111,7 @@ def tas_cubes():
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'EC-Earth3-Veg', 'Amon', 'tas')
-    assert fix == [Tas(None)]
+    assert fix == [Tas(None), GenericFix(None)]
 
 
 def test_tas_fix_metadata(tas_cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_ec_earth3_veg_lr.py b/tests/integration/cmor/_fixes/cmip6/test_ec_earth3_veg_lr.py
index 22abcc7d3..b3f7963a7 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_ec_earth3_veg_lr.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_ec_earth3_veg_lr.py
@@ -1,13 +1,13 @@
 """Test fixes for EC-Earth3-Veg-LR."""
 from esmvalcore.cmor._fixes.cmip6.ec_earth3_veg_lr import Siconc
 from esmvalcore.cmor._fixes.common import OceanFixGrid
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'EC-Earth3-Veg-LR', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_fgoals_f3_l.py b/tests/integration/cmor/_fixes/cmip6/test_fgoals_f3_l.py
index 450158ca7..7e9aa38d0 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_fgoals_f3_l.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_fgoals_f3_l.py
@@ -1,17 +1,13 @@
 """Tests for the fixes of FGOALS-f3-L."""
 
-import numpy as np
 import iris
+import numpy as np
 import pytest
 from cf_units import Unit
 
-from esmvalcore.cmor._fixes.cmip6.fgoals_f3_l import (
-    AllVars,
-    Clt,
-    Sftlf,
-    Tos,
-)
+from esmvalcore.cmor._fixes.cmip6.fgoals_f3_l import AllVars, Clt, Sftlf, Tos
 from esmvalcore.cmor._fixes.common import OceanFixGrid
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -80,7 +76,7 @@ def cubes():
 
 def test_get_allvars_fix():
     fix = Fix.get_fixes('CMIP6', 'FGOALS-f3-L', 'Amon', 'wrong_time_bnds')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_metadata(cubes):
@@ -104,7 +100,7 @@ def test_tos_fix():
 def test_get_clt_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'FGOALS-f3-l', 'Amon', 'clt')
-    assert fix == [Clt(None), AllVars(None)]
+    assert fix == [Clt(None), AllVars(None), GenericFix(None)]
 
 
 @pytest.fixture
@@ -129,7 +125,7 @@ def test_clt_fix_data(clt_cube):
 def test_get_sftlf_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'FGOALS-f3-l', 'Amon', 'sftlf')
-    assert fix == [Sftlf(None), AllVars(None)]
+    assert fix == [Sftlf(None), AllVars(None), GenericFix(None)]
 
 
 def test_sftlf_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_fgoals_g3.py b/tests/integration/cmor/_fixes/cmip6/test_fgoals_g3.py
index 630aa99fc..8bb945702 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_fgoals_g3.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_fgoals_g3.py
@@ -6,6 +6,7 @@ import numpy as np
 
 from esmvalcore.cmor._fixes.cmip6.fgoals_g3 import Mrsos, Siconc, Tos
 from esmvalcore.cmor._fixes.common import OceanFixGrid
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -13,7 +14,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_tos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'Omon', 'tos')
-    assert fix == [Tos(None)]
+    assert fix == [Tos(None), GenericFix(None)]
 
 
 def test_tos_fix():
@@ -56,7 +57,7 @@ def test_tos_fix_metadata(mock_base_fix_metadata):
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'BCC-CSM2-MR', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
@@ -67,7 +68,7 @@ def test_siconc_fix():
 def test_get_mrsos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'FGOALS-g3', 'Lmon', 'mrsos')
-    assert fix == [Mrsos(None)]
+    assert fix == [Mrsos(None), GenericFix(None)]
 
 
 def test_mrsos_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_fio_esm_2_0.py b/tests/integration/cmor/_fixes/cmip6/test_fio_esm_2_0.py
index 36696f122..4ac1d05d4 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_fio_esm_2_0.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_fio_esm_2_0.py
@@ -6,6 +6,7 @@ from cf_units import Unit
 
 from esmvalcore.cmor._fixes.cmip6.fio_esm_2_0 import Amon, Omon, Tos
 from esmvalcore.cmor._fixes.common import OceanFixGrid
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -13,13 +14,13 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'FIO-ESM-2-0', 'Amon', 'tas')
-    assert fix == [Amon(None)]
+    assert fix == [Amon(None), GenericFix(None)]
 
 
 def test_get_tos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'FIO-ESM-2-0', 'Omon', 'tos')
-    assert fix == [OceanFixGrid(None), Omon(None)]
+    assert fix == [OceanFixGrid(None), Omon(None), GenericFix(None)]
 
 
 def test_tos_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_gfdl_cm4.py b/tests/integration/cmor/_fixes/cmip6/test_gfdl_cm4.py
index e52b55a00..f28310c6c 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_gfdl_cm4.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_gfdl_cm4.py
@@ -3,9 +3,16 @@ import iris
 import numpy as np
 import pytest
 
-from esmvalcore.cmor._fixes.cmip6.gfdl_cm4 import (Cl, Cli, Clw,
-                                                   Fgco2, Omon, Siconc)
+from esmvalcore.cmor._fixes.cmip6.gfdl_cm4 import (
+    Cl,
+    Cli,
+    Clw,
+    Fgco2,
+    Omon,
+    Siconc,
+)
 from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -13,7 +20,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GFDL-CM4', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 AIR_PRESSURE_POINTS = np.array([[[[1.0, 1.0],
@@ -75,7 +82,7 @@ def test_cl_fix_metadata(test_data_path):
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GFDL-CM4', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -86,7 +93,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GFDL-CM4', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -97,13 +104,13 @@ def test_clw_fix():
 def test_get_fgco2_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GFDL-CM4', 'Omon', 'fgco2')
-    assert fix == [Fgco2(None), Omon(None)]
+    assert fix == [Fgco2(None), Omon(None), GenericFix(None)]
 
 
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GFDL-CM4', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_gfdl_esm4.py b/tests/integration/cmor/_fixes/cmip6/test_gfdl_esm4.py
index d21323bb1..1db8eca4a 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_gfdl_esm4.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_gfdl_esm4.py
@@ -6,6 +6,7 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.gfdl_esm4 import Fgco2, Omon, Siconc
 from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -13,7 +14,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GFDL-ESM4', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
@@ -52,7 +53,7 @@ def thetao_cubes():
 def test_get_thetao_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GFDL-ESM4', 'Omon', 'thetao')
-    assert fix == [Omon(None)]
+    assert fix == [Omon(None), GenericFix(None)]
 
 
 def test_thetao_fix_metadata(thetao_cubes):
@@ -76,7 +77,7 @@ def test_thetao_fix_metadata(thetao_cubes):
 def test_get_fgco2_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GFDL-ESM4', 'Omon', 'fgco2')
-    assert fix == [Fgco2(None), Omon(None)]
+    assert fix == [Fgco2(None), Omon(None), GenericFix(None)]
 
 
 def test_fgco2_fix_metadata():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_giss_e2_1_g.py b/tests/integration/cmor/_fixes/cmip6/test_giss_e2_1_g.py
index 9c88dc61a..40e61adb8 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_giss_e2_1_g.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_giss_e2_1_g.py
@@ -5,13 +5,13 @@ from iris.cube import Cube
 
 from esmvalcore.cmor._fixes.cmip6.giss_e2_1_g import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GISS-E2-1-G', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -22,7 +22,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GISS-E2-1-G', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -33,7 +33,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GISS-E2-1-G', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -42,7 +42,7 @@ def test_clw_fix():
 
 
 def test_tos_fix():
-    fix, = Fix.get_fixes('CMIP6', 'GISS-E2-1-G', 'Omon', 'tos')
+    fix = Fix.get_fixes('CMIP6', 'GISS-E2-1-G', 'Omon', 'tos')[0]
     cube = Cube(
         da.array([274], dtype=np.float32),
         var_name='tos',
diff --git a/tests/integration/cmor/_fixes/cmip6/test_giss_e2_1_h.py b/tests/integration/cmor/_fixes/cmip6/test_giss_e2_1_h.py
index f8afbeea0..482e72cd2 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_giss_e2_1_h.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_giss_e2_1_h.py
@@ -1,13 +1,13 @@
 """Test fixes for GISS-E2-1-H."""
 from esmvalcore.cmor._fixes.cmip6.giss_e2_1_h import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GISS-E2-1-H', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +18,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GISS-E2-1-H', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +29,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'GISS-E2-1-H', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_hadgem3_gc31_ll.py b/tests/integration/cmor/_fixes/cmip6/test_hadgem3_gc31_ll.py
index a6543060b..aa9e7c34c 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_hadgem3_gc31_ll.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_hadgem3_gc31_ll.py
@@ -4,6 +4,7 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.hadgem3_gc31_ll import AllVars, Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridHeightCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -16,7 +17,7 @@ def sample_cubes():
 
 def test_get_tas_fix():
     fix = Fix.get_fixes('CMIP6', 'HadGEM3-GC31-LL', 'Amon', 'tas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_metadata(sample_cubes):
@@ -40,7 +41,7 @@ def test_allvars_no_need_tofix_metadata(sample_cubes):
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'HadGEM3-GC31-LL', 'Amon', 'cl')
-    assert fix == [Cl(None), AllVars(None)]
+    assert fix == [Cl(None), AllVars(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -51,7 +52,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'HadGEM3-GC31-LL', 'Amon', 'cli')
-    assert fix == [Cli(None), AllVars(None)]
+    assert fix == [Cli(None), AllVars(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -62,7 +63,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'HadGEM3-GC31-LL', 'Amon', 'clw')
-    assert fix == [Clw(None), AllVars(None)]
+    assert fix == [Clw(None), AllVars(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_icon_esm_lr.py b/tests/integration/cmor/_fixes/cmip6/test_icon_esm_lr.py
index 705a8bb5e..dfd183788 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_icon_esm_lr.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_icon_esm_lr.py
@@ -4,6 +4,7 @@ from iris.coords import AuxCoord
 from iris.cube import Cube, CubeList
 
 from esmvalcore.cmor._fixes.cmip6.icon_esm_lr import AllVars
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -34,7 +35,7 @@ def cubes():
 def test_get_allvars_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'ICON-ESM-LR', 'Amon', 'tas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_metadata_lat_lon(cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_iitm_esm.py b/tests/integration/cmor/_fixes/cmip6/test_iitm_esm.py
index 52380e87f..16efd1d75 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_iitm_esm.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_iitm_esm.py
@@ -6,6 +6,7 @@ from cf_units import Unit
 
 from esmvalcore.cmor._fixes.cmip6.iitm_esm import AllVars, Tos
 from esmvalcore.cmor._fixes.common import OceanFixGrid
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -16,7 +17,7 @@ def test_get_tos_fix():
                         'Omon',
                         'tos',
                         extra_facets={"frequency": "mon"})
-    assert fix == [Tos(None), AllVars(None)]
+    assert fix == [Tos(None), AllVars(None), GenericFix(None)]
 
 
 def test_tos_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_ipsl_cm6a_lr.py b/tests/integration/cmor/_fixes/cmip6/test_ipsl_cm6a_lr.py
index 99f2a76aa..c32008ef0 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_ipsl_cm6a_lr.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_ipsl_cm6a_lr.py
@@ -9,7 +9,7 @@ from iris.cube import Cube, CubeList
 from iris.exceptions import CoordinateNotFoundError
 
 from esmvalcore.cmor._fixes.cmip6.ipsl_cm6a_lr import AllVars, Clcalipso, Omon
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 from esmvalcore.cmor.table import get_var_info
 
 
@@ -79,7 +79,7 @@ class TestAllVars(unittest.TestCase):
 def test_get_clcalipso_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'IPSL-CM6A-LR', 'CFmon', 'clcalipso')
-    assert fix == [Clcalipso(None), AllVars(None)]
+    assert fix == [Clcalipso(None), AllVars(None), GenericFix(None)]
 
 
 @pytest.fixture
@@ -137,7 +137,7 @@ def thetao_cubes():
 def test_get_thetao_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'IPSL-CM6A-LR', 'Omon', 'thetao')
-    assert fix == [Omon(None), AllVars(None)]
+    assert fix == [Omon(None), AllVars(None), GenericFix(None)]
 
 
 def test_thetao_fix_metadata(thetao_cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_kace_1_0_g.py b/tests/integration/cmor/_fixes/cmip6/test_kace_1_0_g.py
index 21e35f0c0..5d6b4641d 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_kace_1_0_g.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_kace_1_0_g.py
@@ -6,13 +6,14 @@ from cf_units import Unit
 
 from esmvalcore.cmor._fixes.cmip6.kace_1_0_g import AllVars, Cl, Cli, Clw, Tos
 from esmvalcore.cmor._fixes.common import ClFixHybridHeightCoord, OceanFixGrid
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'KACE-1-0-G', 'Amon', 'cl')
-    assert fix == [Cl(None), AllVars(None)]
+    assert fix == [Cl(None), AllVars(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -23,7 +24,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'KACE-1-0-G', 'Amon', 'cli')
-    assert fix == [Cli(None), AllVars(None)]
+    assert fix == [Cli(None), AllVars(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -34,7 +35,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'KACE-1-0-G', 'Amon', 'clw')
-    assert fix == [Clw(None), AllVars(None)]
+    assert fix == [Clw(None), AllVars(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -45,7 +46,7 @@ def test_clw_fix():
 def test_get_tos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'KACE-1-0-G', 'Omon', 'tos')
-    assert fix == [Tos(None), AllVars(None)]
+    assert fix == [Tos(None), AllVars(None), GenericFix(None)]
 
 
 def test_tos_fix():
@@ -101,7 +102,7 @@ def tos_cubes():
 
 def test_get_allvars_fix():
     fix = Fix.get_fixes('CMIP6', 'KACE-1-0-G', 'Omon', 'tos')
-    assert fix == [OceanFixGrid(None), AllVars(None)]
+    assert fix == [OceanFixGrid(None), AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_metadata(monkeypatch, tos_cubes, caplog):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_kiost_esm.py b/tests/integration/cmor/_fixes/cmip6/test_kiost_esm.py
index 9b460db15..80af6436e 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_kiost_esm.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_kiost_esm.py
@@ -8,7 +8,7 @@ from iris.cube import Cube, CubeList
 
 from esmvalcore.cmor._fixes.cmip6.kiost_esm import SfcWind, Siconc, Tas
 from esmvalcore.cmor._fixes.common import SiconcFixScalarCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 from esmvalcore.cmor.table import get_var_info
 
 
@@ -72,7 +72,7 @@ def tas_cubes():
 
 def test_get_sfcwind_fix():
     fix = Fix.get_fixes('CMIP6', 'KIOST-ESM', 'Amon', 'sfcWind')
-    assert fix == [SfcWind(None)]
+    assert fix == [SfcWind(None), GenericFix(None)]
 
 
 def test_sfcwind_fix_metadata(sfcwind_cubes):
@@ -104,7 +104,7 @@ def test_sfcwind_fix_metadata(sfcwind_cubes):
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'KIOST-ESM', 'SImon', 'siconc')
-    assert fix == [Siconc(None)]
+    assert fix == [Siconc(None), GenericFix(None)]
 
 
 def test_siconc_fix():
@@ -127,7 +127,7 @@ def test_siconc_fix_data():
 
 def test_get_tas_fix():
     fix = Fix.get_fixes('CMIP6', 'KIOST-ESM', 'Amon', 'tas')
-    assert fix == [Tas(None)]
+    assert fix == [Tas(None), GenericFix(None)]
 
 
 def test_tas_fix_metadata(tas_cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_mcm_ua_1_0.py b/tests/integration/cmor/_fixes/cmip6/test_mcm_ua_1_0.py
index bbb1a98f3..85eed2533 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_mcm_ua_1_0.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_mcm_ua_1_0.py
@@ -5,6 +5,7 @@ import pytest
 from cf_units import Unit
 
 from esmvalcore.cmor._fixes.cmip6.mcm_ua_1_0 import AllVars, Omon, Tas, Uas
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -119,17 +120,17 @@ def cubes_bounds():
 def test_get_allvars_fix():
     fix = Fix.get_fixes('CMIP6', 'MCM-UA-1-0', 'Amon',
                         'arbitrary_var_name_and_wrong_lon_bnds')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_get_tas_fix():
     fix = Fix.get_fixes('CMIP6', 'MCM-UA-1-0', 'Amon', 'tas')
-    assert fix == [Tas(None), AllVars(None)]
+    assert fix == [Tas(None), AllVars(None), GenericFix(None)]
 
 
 def test_get_uas_fix():
     fix = Fix.get_fixes('CMIP6', 'MCM-UA-1-0', 'Amon', 'uas')
-    assert fix == [Uas(None), AllVars(None)]
+    assert fix == [Uas(None), AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_metadata(cubes):
@@ -265,7 +266,7 @@ def thetao_cubes():
 def test_get_thetao_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MCM-UA-1-0', 'Omon', 'thetao')
-    assert fix == [Omon(None), AllVars(None)]
+    assert fix == [Omon(None), AllVars(None), GenericFix(None)]
 
 
 def test_thetao_fix_metadata(thetao_cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_miroc6.py b/tests/integration/cmor/_fixes/cmip6/test_miroc6.py
index 9c021d9ce..26662a0ec 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_miroc6.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_miroc6.py
@@ -5,14 +5,14 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.miroc6 import Cl, Cli, Clw, Tos
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 from esmvalcore.cmor.table import get_var_info
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MIROC6', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -23,7 +23,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MIROC6', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -34,7 +34,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MIROC6', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -69,7 +69,7 @@ def tos_cubes():
 def test_get_tos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MIROC6', 'Omon', 'tos')
-    assert fix == [Tos(None)]
+    assert fix == [Tos(None), GenericFix(None)]
 
 
 def test_tos_fix_metadata(tos_cubes):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_miroc_es2l.py b/tests/integration/cmor/_fixes/cmip6/test_miroc_es2l.py
index 550f01d80..22ae2d1c0 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_miroc_es2l.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_miroc_es2l.py
@@ -1,13 +1,13 @@
 """Test fixes for MIROC-ES2L."""
 from esmvalcore.cmor._fixes.cmip6.miroc_es2l import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MIROC-ES2L', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +18,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MIROC-ES2L', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +29,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MIROC-ES2L', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_mpi_esm1_2_lr.py b/tests/integration/cmor/_fixes/cmip6/test_mpi_esm1_2_lr.py
index 0f05c763c..2ae3af935 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_mpi_esm1_2_lr.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_mpi_esm1_2_lr.py
@@ -1,13 +1,14 @@
 """Tests for the fixes of MPI-ESM1-2-LR."""
 from esmvalcore.cmor._fixes.cmip6.mpi_esm1_2_lr import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MPI-ESM1-2-LR', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +19,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MPI-ESM1-2-LR', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +30,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MPI-ESM1-2-LR', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_mpi_esm_1_2_ham.py b/tests/integration/cmor/_fixes/cmip6/test_mpi_esm_1_2_ham.py
index 492aa45f5..358cb1f56 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_mpi_esm_1_2_ham.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_mpi_esm_1_2_ham.py
@@ -1,13 +1,14 @@
 """Tests for the fixes of MPI-ESM-1-2-HAM."""
 from esmvalcore.cmor._fixes.cmip6.mpi_esm_1_2_ham import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MPI-ESM-1-2-HAM', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +19,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MPI-ESM-1-2-HAM', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +30,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MPI-ESM-1-2-HAM', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_mri_esm2_0.py b/tests/integration/cmor/_fixes/cmip6/test_mri_esm2_0.py
index 609cd12ab..6ec68855b 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_mri_esm2_0.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_mri_esm2_0.py
@@ -1,13 +1,13 @@
 """Test fixes for MRI-ESM2-0."""
 from esmvalcore.cmor._fixes.cmip6.mri_esm2_0 import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MRI-ESM2-0', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +18,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MRI-ESM2-0', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +29,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'MRI-ESM2-0', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_nesm3.py b/tests/integration/cmor/_fixes/cmip6/test_nesm3.py
index c1e1fe5f9..bc9265bc5 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_nesm3.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_nesm3.py
@@ -1,13 +1,13 @@
 """Test fixes for NESM3."""
 from esmvalcore.cmor._fixes.cmip6.nesm3 import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NESM3', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +18,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NESM3', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +29,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NESM3', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_noresm2_lm.py b/tests/integration/cmor/_fixes/cmip6/test_noresm2_lm.py
index c77e945de..78ea66eff 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_noresm2_lm.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_noresm2_lm.py
@@ -12,6 +12,7 @@ from esmvalcore.cmor._fixes.cmip6.noresm2_lm import (
     Siconc,
 )
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
 
@@ -19,7 +20,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NorESM2-LM', 'Amon', 'cl')
-    assert fix == [Cl(None), AllVars(None)]
+    assert fix == [Cl(None), AllVars(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -30,7 +31,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NorESM2-LM', 'Amon', 'cli')
-    assert fix == [Cli(None), AllVars(None)]
+    assert fix == [Cli(None), AllVars(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -41,7 +42,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NorESM2-LM', 'Amon', 'clw')
-    assert fix == [Clw(None), AllVars(None)]
+    assert fix == [Clw(None), AllVars(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -97,7 +98,7 @@ def cubes_bounds():
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NorESM2-LM', 'SImon', 'siconc')
-    assert fix == [Siconc(None), AllVars(None)]
+    assert fix == [Siconc(None), AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_lon_bounds(cubes_bounds):
diff --git a/tests/integration/cmor/_fixes/cmip6/test_noresm2_mm.py b/tests/integration/cmor/_fixes/cmip6/test_noresm2_mm.py
index 2fd3a9c7f..0868dd910 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_noresm2_mm.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_noresm2_mm.py
@@ -1,13 +1,14 @@
 """Tests for the fixes of NorESM2-MM."""
 from esmvalcore.cmor._fixes.cmip6.noresm2_mm import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NorESM2-MM', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +19,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NorESM2-MM', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +30,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'NorESM2-MM', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_sam0_unicon.py b/tests/integration/cmor/_fixes/cmip6/test_sam0_unicon.py
index 09d35be72..e9f0a76a5 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_sam0_unicon.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_sam0_unicon.py
@@ -5,13 +5,13 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.sam0_unicon import Cl, Cli, Clw, Nbp
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
-from esmvalcore.cmor._fixes.fix import Fix
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'SAM0-UNICON', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -22,7 +22,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'SAM0-UNICON', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -33,7 +33,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'SAM0-UNICON', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
@@ -44,7 +44,7 @@ def test_clw_fix():
 def test_get_nbp_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'SAM0-UNICON', 'Lmon', 'nbp')
-    assert fix == [Nbp(None)]
+    assert fix == [Nbp(None), GenericFix(None)]
 
 
 @pytest.fixture
diff --git a/tests/integration/cmor/_fixes/cmip6/test_taiesm1.py b/tests/integration/cmor/_fixes/cmip6/test_taiesm1.py
index 107db534b..dd955ef1f 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_taiesm1.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_taiesm1.py
@@ -1,13 +1,14 @@
 """Tests for the fixes of TaiESM1."""
 from esmvalcore.cmor._fixes.cmip6.taiesm1 import Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridPressureCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'TaiESM1', 'Amon', 'cl')
-    assert fix == [Cl(None)]
+    assert fix == [Cl(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -18,7 +19,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'TaiESM1', 'Amon', 'cli')
-    assert fix == [Cli(None)]
+    assert fix == [Cli(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -29,7 +30,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'TaiESM1', 'Amon', 'clw')
-    assert fix == [Clw(None)]
+    assert fix == [Clw(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/cmip6/test_ukesm1_0_ll.py b/tests/integration/cmor/_fixes/cmip6/test_ukesm1_0_ll.py
index f6aceb121..423d55e63 100644
--- a/tests/integration/cmor/_fixes/cmip6/test_ukesm1_0_ll.py
+++ b/tests/integration/cmor/_fixes/cmip6/test_ukesm1_0_ll.py
@@ -4,6 +4,7 @@ import pytest
 
 from esmvalcore.cmor._fixes.cmip6.ukesm1_0_ll import AllVars, Cl, Cli, Clw
 from esmvalcore.cmor._fixes.common import ClFixHybridHeightCoord
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 
 
@@ -18,7 +19,7 @@ def sample_cubes():
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'UKESM1-0-LL', 'Amon', 'tas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_metadata(sample_cubes):
@@ -44,7 +45,7 @@ def test_allvars_no_need_tofix_metadata(sample_cubes):
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'UKESM1-0-LL', 'Amon', 'cl')
-    assert fix == [Cl(None), AllVars(None)]
+    assert fix == [Cl(None), AllVars(None), GenericFix(None)]
 
 
 def test_cl_fix():
@@ -55,7 +56,7 @@ def test_cl_fix():
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'UKESM1-0-LL', 'Amon', 'cli')
-    assert fix == [Cli(None), AllVars(None)]
+    assert fix == [Cli(None), AllVars(None), GenericFix(None)]
 
 
 def test_cli_fix():
@@ -66,7 +67,7 @@ def test_cli_fix():
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('CMIP6', 'UKESM1-0-LL', 'Amon', 'clw')
-    assert fix == [Clw(None), AllVars(None)]
+    assert fix == [Clw(None), AllVars(None), GenericFix(None)]
 
 
 def test_clw_fix():
diff --git a/tests/integration/cmor/_fixes/emac/test_emac.py b/tests/integration/cmor/_fixes/emac/test_emac.py
index 15c5b76a6..1146502a4 100644
--- a/tests/integration/cmor/_fixes/emac/test_emac.py
+++ b/tests/integration/cmor/_fixes/emac/test_emac.py
@@ -36,6 +36,7 @@ from esmvalcore.cmor._fixes.emac.emac import (
     Toz,
     Zg,
 )
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import CoordinateInfo, get_var_info
 from esmvalcore.config._config import get_extra_facets
@@ -834,7 +835,7 @@ def test_sample_data_ta_alevel(test_data_path, tmp_path):
 def test_get_awhea_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Omon', 'awhea')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_awhea_fix(cubes_2d):
@@ -859,7 +860,7 @@ def test_awhea_fix(cubes_2d):
 def test_get_clivi_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'clivi')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_clivi_fix(cubes_2d):
@@ -883,7 +884,7 @@ def test_clivi_fix(cubes_2d):
 def test_get_clt_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'clt')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_clt_fix(cubes_2d):
@@ -906,7 +907,7 @@ def test_clt_fix(cubes_2d):
 def test_get_clwvi_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'clwvi')
-    assert fix == [Clwvi(None), AllVars(None)]
+    assert fix == [Clwvi(None), AllVars(None), GenericFix(None)]
 
 
 def test_clwvi_fix(cubes_2d):
@@ -933,7 +934,7 @@ def test_clwvi_fix(cubes_2d):
 def test_get_co2mass_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'co2mass')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_co2mass_fix(cubes_1d):
@@ -957,7 +958,7 @@ def test_co2mass_fix(cubes_1d):
 def test_get_evspsbl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'evspsbl')
-    assert fix == [Evspsbl(None), AllVars(None)]
+    assert fix == [Evspsbl(None), AllVars(None), GenericFix(None)]
 
 
 def test_evspsbl_fix(cubes_2d):
@@ -986,7 +987,7 @@ def test_evspsbl_fix(cubes_2d):
 def test_get_hfls_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'hfls')
-    assert fix == [Hfls(None), AllVars(None)]
+    assert fix == [Hfls(None), AllVars(None), GenericFix(None)]
 
 
 def test_hfls_fix(cubes_2d):
@@ -1014,7 +1015,7 @@ def test_hfls_fix(cubes_2d):
 def test_get_hfss_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'hfss')
-    assert fix == [Hfss(None), AllVars(None)]
+    assert fix == [Hfss(None), AllVars(None), GenericFix(None)]
 
 
 def test_hfss_fix(cubes_2d):
@@ -1042,7 +1043,7 @@ def test_hfss_fix(cubes_2d):
 def test_get_hurs_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'hurs')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_hurs_fix(cubes_2d):
@@ -1065,7 +1066,7 @@ def test_hurs_fix(cubes_2d):
 def test_get_od550aer_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'od550aer')
-    assert fix == [Od550aer(None), AllVars(None)]
+    assert fix == [Od550aer(None), AllVars(None), GenericFix(None)]
 
 
 def test_od550aer_fix(cubes_3d):
@@ -1090,7 +1091,7 @@ def test_od550aer_fix(cubes_3d):
 def test_get_pr_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'pr')
-    assert fix == [Pr(None), AllVars(None)]
+    assert fix == [Pr(None), AllVars(None), GenericFix(None)]
 
 
 def test_pr_fix(cubes_2d):
@@ -1116,7 +1117,7 @@ def test_pr_fix(cubes_2d):
 def test_get_prc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'prc')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_prc_fix(cubes_2d):
@@ -1140,7 +1141,7 @@ def test_prc_fix(cubes_2d):
 def test_get_prl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'prl')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_prl_fix(cubes_2d):
@@ -1164,7 +1165,7 @@ def test_prl_fix(cubes_2d):
 def test_get_prsn_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'prsn')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_prsn_fix(cubes_2d):
@@ -1188,7 +1189,7 @@ def test_prsn_fix(cubes_2d):
 def test_get_prw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'prw')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_prw_fix(cubes_2d):
@@ -1212,7 +1213,7 @@ def test_prw_fix(cubes_2d):
 def test_get_ps_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'ps')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_ps_fix(cubes_2d):
@@ -1236,7 +1237,7 @@ def test_ps_fix(cubes_2d):
 def test_get_psl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'psl')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_psl_fix(cubes_2d):
@@ -1260,7 +1261,7 @@ def test_psl_fix(cubes_2d):
 def test_get_rlds_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rlds')
-    assert fix == [Rlds(None), AllVars(None)]
+    assert fix == [Rlds(None), AllVars(None), GenericFix(None)]
 
 
 def test_rlds_fix(cubes_2d):
@@ -1285,7 +1286,7 @@ def test_rlds_fix(cubes_2d):
 def test_get_rlus_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rlus')
-    assert fix == [Rlus(None), AllVars(None)]
+    assert fix == [Rlus(None), AllVars(None), GenericFix(None)]
 
 
 def test_rlus_fix(cubes_2d):
@@ -1313,7 +1314,7 @@ def test_rlus_fix(cubes_2d):
 def test_get_rlut_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rlut')
-    assert fix == [Rlut(None), AllVars(None)]
+    assert fix == [Rlut(None), AllVars(None), GenericFix(None)]
 
 
 def test_rlut_fix(cubes_2d):
@@ -1341,7 +1342,7 @@ def test_rlut_fix(cubes_2d):
 def test_get_rlutcs_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rlutcs')
-    assert fix == [Rlutcs(None), AllVars(None)]
+    assert fix == [Rlutcs(None), AllVars(None), GenericFix(None)]
 
 
 def test_rlutcs_fix(cubes_2d):
@@ -1370,7 +1371,7 @@ def test_rlutcs_fix(cubes_2d):
 def test_get_rsds_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rsds')
-    assert fix == [Rsds(None), AllVars(None)]
+    assert fix == [Rsds(None), AllVars(None), GenericFix(None)]
 
 
 def test_rsds_fix(cubes_2d):
@@ -1395,7 +1396,7 @@ def test_rsds_fix(cubes_2d):
 def test_get_rsdt_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rsdt')
-    assert fix == [Rsdt(None), AllVars(None)]
+    assert fix == [Rsdt(None), AllVars(None), GenericFix(None)]
 
 
 def test_rsdt_fix(cubes_2d):
@@ -1420,7 +1421,7 @@ def test_rsdt_fix(cubes_2d):
 def test_get_rsus_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rsus')
-    assert fix == [Rsus(None), AllVars(None)]
+    assert fix == [Rsus(None), AllVars(None), GenericFix(None)]
 
 
 def test_rsus_fix(cubes_2d):
@@ -1448,7 +1449,7 @@ def test_rsus_fix(cubes_2d):
 def test_get_rsut_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rsut')
-    assert fix == [Rsut(None), AllVars(None)]
+    assert fix == [Rsut(None), AllVars(None), GenericFix(None)]
 
 
 def test_rsut_fix(cubes_2d):
@@ -1476,7 +1477,7 @@ def test_rsut_fix(cubes_2d):
 def test_get_rsutcs_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rsutcs')
-    assert fix == [Rsutcs(None), AllVars(None)]
+    assert fix == [Rsutcs(None), AllVars(None), GenericFix(None)]
 
 
 def test_rsutcs_fix(cubes_2d):
@@ -1505,7 +1506,7 @@ def test_rsutcs_fix(cubes_2d):
 def test_get_rtmt_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'rtmt')
-    assert fix == [Rtmt(None), AllVars(None)]
+    assert fix == [Rtmt(None), AllVars(None), GenericFix(None)]
 
 
 def test_rtmt_fix(cubes_2d):
@@ -1531,7 +1532,7 @@ def test_rtmt_fix(cubes_2d):
 def test_get_sfcWind_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'sfcWind')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_sfcWind_fix(cubes_2d):  # noqa: N802
@@ -1557,7 +1558,7 @@ def test_sfcWind_fix(cubes_2d):  # noqa: N802
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'SImon', 'siconc')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_siconc_fix(cubes_2d):
@@ -1582,7 +1583,7 @@ def test_siconc_fix(cubes_2d):
 def test_get_siconca_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'SImon', 'siconca')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_siconca_fix(cubes_2d):
@@ -1607,7 +1608,7 @@ def test_siconca_fix(cubes_2d):
 def test_get_sithick_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'SImon', 'sithick')
-    assert fix == [Sithick(None), AllVars(None)]
+    assert fix == [Sithick(None), AllVars(None), GenericFix(None)]
 
 
 def test_sithick_fix(cubes_2d):
@@ -1642,7 +1643,7 @@ def test_sithick_fix(cubes_2d):
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'tas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_tas_fix(cubes_2d):
@@ -1668,7 +1669,7 @@ def test_tas_fix(cubes_2d):
 def test_get_tasmax_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'tasmax')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_tasmax_fix(cubes_2d):
@@ -1694,7 +1695,7 @@ def test_tasmax_fix(cubes_2d):
 def test_get_tasmin_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'tasmin')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_tasmin_fix(cubes_2d):
@@ -1720,7 +1721,7 @@ def test_tasmin_fix(cubes_2d):
 def test_get_tauu_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'tauu')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_tauu_fix(cubes_2d):
@@ -1744,7 +1745,7 @@ def test_tauu_fix(cubes_2d):
 def test_get_tauv_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'tauv')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_tauv_fix(cubes_2d):
@@ -1768,7 +1769,7 @@ def test_tauv_fix(cubes_2d):
 def test_get_tos_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Omon', 'tos')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_tos_fix(cubes_2d):
@@ -1792,7 +1793,7 @@ def test_tos_fix(cubes_2d):
 def test_get_toz_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'AERmon', 'toz')
-    assert fix == [Toz(None), AllVars(None)]
+    assert fix == [Toz(None), AllVars(None), GenericFix(None)]
 
 
 def test_toz_fix(cubes_2d):
@@ -1816,7 +1817,7 @@ def test_toz_fix(cubes_2d):
 def test_get_ts_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'ts')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_ts_fix(cubes_2d):
@@ -1840,7 +1841,7 @@ def test_ts_fix(cubes_2d):
 def test_get_uas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'uas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_uas_fix(cubes_2d):
@@ -1866,7 +1867,7 @@ def test_uas_fix(cubes_2d):
 def test_get_vas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'vas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_vas_fix(cubes_2d):
@@ -1895,7 +1896,7 @@ def test_vas_fix(cubes_2d):
 def test_get_MP_BC_tot_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_BC_tot')
-    assert fix == [MP_BC_tot(None), AllVars(None)]
+    assert fix == [MP_BC_tot(None), AllVars(None), GenericFix(None)]
 
 
 def test_MP_BC_tot_fix(cubes_1d):  # noqa: N802
@@ -1925,7 +1926,7 @@ def test_MP_BC_tot_fix(cubes_1d):  # noqa: N802
 def test_get_MP_CFCl3_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_CFCl3')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_CFCl3_fix(cubes_1d):  # noqa: N802
@@ -1949,7 +1950,7 @@ def test_MP_CFCl3_fix(cubes_1d):  # noqa: N802
 def test_get_MP_ClOX_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_ClOX')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_ClOX_fix(cubes_1d):  # noqa: N802
@@ -1973,7 +1974,7 @@ def test_MP_ClOX_fix(cubes_1d):  # noqa: N802
 def test_get_MP_CH4_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_CH4')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_CH4_fix(cubes_1d):  # noqa: N802
@@ -1997,7 +1998,7 @@ def test_MP_CH4_fix(cubes_1d):  # noqa: N802
 def test_get_MP_CO_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_CO')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_CO_fix(cubes_1d):  # noqa: N802
@@ -2021,7 +2022,7 @@ def test_MP_CO_fix(cubes_1d):  # noqa: N802
 def test_get_MP_CO2_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_CO2')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_CO2_fix(cubes_1d):  # noqa: N802
@@ -2045,7 +2046,7 @@ def test_MP_CO2_fix(cubes_1d):  # noqa: N802
 def test_get_MP_DU_tot_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_DU_tot')
-    assert fix == [MP_DU_tot(None), AllVars(None)]
+    assert fix == [MP_DU_tot(None), AllVars(None), GenericFix(None)]
 
 
 def test_MP_DU_tot_fix(cubes_1d):  # noqa: N802
@@ -2076,7 +2077,7 @@ def test_MP_DU_tot_fix(cubes_1d):  # noqa: N802
 def test_get_MP_N2O_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_N2O')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_N2O_fix(cubes_1d):  # noqa: N802
@@ -2100,7 +2101,7 @@ def test_MP_N2O_fix(cubes_1d):  # noqa: N802
 def test_get_MP_NH3_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_NH3')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_NH3_fix(cubes_1d):  # noqa: N802
@@ -2124,7 +2125,7 @@ def test_MP_NH3_fix(cubes_1d):  # noqa: N802
 def test_get_MP_NO_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_NO')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_NO_fix(cubes_1d):  # noqa: N802
@@ -2148,7 +2149,7 @@ def test_MP_NO_fix(cubes_1d):  # noqa: N802
 def test_get_MP_NO2_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_NO2')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_NO2_fix(cubes_1d):  # noqa: N802
@@ -2172,7 +2173,7 @@ def test_MP_NO2_fix(cubes_1d):  # noqa: N802
 def test_get_MP_NOX_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_NOX')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_NOX_fix(cubes_1d):  # noqa: N802
@@ -2196,7 +2197,7 @@ def test_MP_NOX_fix(cubes_1d):  # noqa: N802
 def test_get_MP_O3_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_O3')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_O3_fix(cubes_1d):  # noqa: N802
@@ -2220,7 +2221,7 @@ def test_MP_O3_fix(cubes_1d):  # noqa: N802
 def test_get_MP_OH_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_OH')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_OH_fix(cubes_1d):  # noqa: N802
@@ -2244,7 +2245,7 @@ def test_MP_OH_fix(cubes_1d):  # noqa: N802
 def test_get_MP_S_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_S')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_S_fix(cubes_1d):  # noqa: N802
@@ -2268,7 +2269,7 @@ def test_MP_S_fix(cubes_1d):  # noqa: N802
 def test_get_MP_SO2_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_SO2')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_MP_SO2_fix(cubes_1d):  # noqa: N802
@@ -2292,7 +2293,7 @@ def test_MP_SO2_fix(cubes_1d):  # noqa: N802
 def test_get_MP_SO4mm_tot_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_SO4mm_tot')
-    assert fix == [MP_SO4mm_tot(None), AllVars(None)]
+    assert fix == [MP_SO4mm_tot(None), AllVars(None), GenericFix(None)]
 
 
 def test_MP_SO4mm_tot_fix(cubes_1d):  # noqa: N802
@@ -2323,7 +2324,7 @@ def test_MP_SO4mm_tot_fix(cubes_1d):  # noqa: N802
 def test_get_MP_SS_tot_fix():  # noqa: N802
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'TRAC10hr', 'MP_SS_tot')
-    assert fix == [MP_SS_tot(None), AllVars(None)]
+    assert fix == [MP_SS_tot(None), AllVars(None), GenericFix(None)]
 
 
 def test_MP_SS_tot_fix(cubes_1d):  # noqa: N802
@@ -2355,7 +2356,7 @@ def test_MP_SS_tot_fix(cubes_1d):  # noqa: N802
 def test_get_cl_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'cl')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_cl_fix(cubes_3d):
@@ -2380,7 +2381,7 @@ def test_cl_fix(cubes_3d):
 def test_get_cli_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'cli')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_cli_fix(cubes_3d):
@@ -2406,7 +2407,7 @@ def test_cli_fix(cubes_3d):
 def test_get_clw_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'clw')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_clw_fix(cubes_3d):
@@ -2432,7 +2433,7 @@ def test_clw_fix(cubes_3d):
 def test_get_hur_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'hur')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_hur_fix(cubes_3d):
@@ -2459,7 +2460,7 @@ def test_hur_fix(cubes_3d):
 def test_get_hus_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'hus')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_hus_fix(cubes_3d):
@@ -2486,7 +2487,7 @@ def test_hus_fix(cubes_3d):
 def test_get_ta_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'ta')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_ta_fix(cubes_3d):
@@ -2513,7 +2514,7 @@ def test_ta_fix(cubes_3d):
 def test_get_ua_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'ua')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_ua_fix(cubes_3d):
@@ -2540,7 +2541,7 @@ def test_ua_fix(cubes_3d):
 def test_get_va_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'va')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_va_fix(cubes_3d):
@@ -2567,7 +2568,7 @@ def test_va_fix(cubes_3d):
 def test_get_zg_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('EMAC', 'EMAC', 'Amon', 'zg')
-    assert fix == [Zg(None), AllVars(None)]
+    assert fix == [Zg(None), AllVars(None), GenericFix(None)]
 
 
 def test_zg_fix(cubes_3d):
diff --git a/tests/integration/cmor/_fixes/icon/test_icon.py b/tests/integration/cmor/_fixes/icon/test_icon.py
index 297058a9a..be20131e5 100644
--- a/tests/integration/cmor/_fixes/icon/test_icon.py
+++ b/tests/integration/cmor/_fixes/icon/test_icon.py
@@ -12,6 +12,7 @@ from iris.coords import AuxCoord, CellMethod, DimCoord
 from iris.cube import Cube, CubeList
 
 import esmvalcore.cmor._fixes.icon.icon
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor._fixes.icon._base_fixes import IconFix
 from esmvalcore.cmor._fixes.icon.icon import AllVars, Clwvi
 from esmvalcore.cmor.fix import Fix
@@ -491,7 +492,7 @@ def check_typesi(cube):
 def test_get_areacella_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'fx', 'areacella')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_areacella_fix(cubes_grid):
@@ -513,7 +514,7 @@ def test_areacella_fix(cubes_grid):
 def test_get_areacello_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'Ofx', 'areacello')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_areacello_fix(cubes_grid):
@@ -538,7 +539,7 @@ def test_areacello_fix(cubes_grid):
 def test_get_clwvi_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'Amon', 'clwvi')
-    assert fix == [Clwvi(None), AllVars(None)]
+    assert fix == [Clwvi(None), AllVars(None), GenericFix(None)]
 
 
 def test_clwvi_fix(cubes_regular_grid):
@@ -572,7 +573,7 @@ def test_clwvi_fix(cubes_regular_grid):
 def test_get_lwp_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'AERmon', 'lwp')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_lwp_fix(cubes_2d):
@@ -599,7 +600,7 @@ def test_lwp_fix(cubes_2d):
 def test_get_rsdt_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'Amon', 'rsdt')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_rsdt_fix(cubes_2d):
@@ -622,7 +623,7 @@ def test_rsdt_fix(cubes_2d):
 def test_get_rsut_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'Amon', 'rsut')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_rsut_fix(cubes_2d):
@@ -648,7 +649,7 @@ def test_rsut_fix(cubes_2d):
 def test_get_siconc_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'SImon', 'siconc')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_siconc_fix(cubes_2d):
@@ -671,7 +672,7 @@ def test_siconc_fix(cubes_2d):
 def test_get_siconca_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'SImon', 'siconca')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_siconca_fix(cubes_2d):
@@ -697,7 +698,7 @@ def test_siconca_fix(cubes_2d):
 def test_get_ta_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'Amon', 'ta')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_ta_fix(cubes_3d):
@@ -732,7 +733,7 @@ def test_ta_fix_no_plev_bounds(cubes_3d):
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'Amon', 'tas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_tas_fix(cubes_2d):
@@ -854,7 +855,7 @@ def test_tas_no_shift_time(cubes_2d):
 def test_get_uas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'Amon', 'uas')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_uas_fix(cubes_2d):
@@ -951,7 +952,7 @@ def test_2d_lat_lon_grid_fix(cubes_2d_lat_lon_grid):
 def test_get_ch4clim_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('ICON', 'ICON', 'Amon', 'ch4Clim')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_ch4clim_fix(cubes_regular_grid):
diff --git a/tests/integration/cmor/_fixes/ipslcm/test_ipsl_cm6.py b/tests/integration/cmor/_fixes/ipslcm/test_ipsl_cm6.py
index f136114bc..dd1d19480 100644
--- a/tests/integration/cmor/_fixes/ipslcm/test_ipsl_cm6.py
+++ b/tests/integration/cmor/_fixes/ipslcm/test_ipsl_cm6.py
@@ -2,6 +2,7 @@
 import iris
 import pytest
 
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor._fixes.ipslcm.ipsl_cm6 import Tas
 from esmvalcore.cmor.fix import Fix
 from esmvalcore.cmor.table import get_var_info
@@ -11,7 +12,7 @@ from esmvalcore.cmor.table import get_var_info
 def test_get_tas_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('IPSLCM', 'IPSL-CM6', 'Amon', 'tas')
-    assert fix == [Tas(None)]
+    assert fix == [Tas(None), GenericFix(None)]
 
 
 @pytest.fixture
diff --git a/tests/integration/cmor/_fixes/native6/test_era5.py b/tests/integration/cmor/_fixes/native6/test_era5.py
index cfe20e7fd..6b8a4922b 100644
--- a/tests/integration/cmor/_fixes/native6/test_era5.py
+++ b/tests/integration/cmor/_fixes/native6/test_era5.py
@@ -6,14 +6,16 @@ import numpy as np
 import pytest
 from cf_units import Unit
 
+from esmvalcore.cmor._fixes.fix import Fix, GenericFix
 from esmvalcore.cmor._fixes.native6.era5 import (
     AllVars,
     Evspsbl,
     Zg,
     get_frequency,
 )
-from esmvalcore.cmor.fix import Fix, fix_metadata
-from esmvalcore.cmor.table import CMOR_TABLES
+from esmvalcore.cmor.fix import fix_metadata
+from esmvalcore.cmor.table import CMOR_TABLES, get_var_info
+from esmvalcore.preprocessor import cmor_check_metadata
 
 COMMENT = ('Contains modified Copernicus Climate Change Service Information '
            f'{datetime.datetime.now().year}')
@@ -22,13 +24,15 @@ COMMENT = ('Contains modified Copernicus Climate Change Service Information '
 def test_get_evspsbl_fix():
     """Test whether the right fixes are gathered for a single variable."""
     fix = Fix.get_fixes('native6', 'ERA5', 'E1hr', 'evspsbl')
-    assert fix == [Evspsbl(None), AllVars(None)]
+    vardef = get_var_info('native6', 'E1hr', 'evspsbl')
+    assert fix == [Evspsbl(vardef), AllVars(vardef), GenericFix(vardef)]
 
 
 def test_get_zg_fix():
     """Test whether the right fix gets found again, for zg as well."""
     fix = Fix.get_fixes('native6', 'ERA5', 'Amon', 'zg')
-    assert fix == [Zg(None), AllVars(None)]
+    vardef = get_var_info('native6', 'E1hr', 'evspsbl')
+    assert fix == [Zg(vardef), AllVars(vardef), GenericFix(vardef)]
 
 
 def test_get_frequency_hourly():
@@ -1027,9 +1031,14 @@ VARIABLES = [
 def test_cmorization(era5_cubes, cmor_cubes, var, mip):
     """Verify that cmorization results in the expected target cube."""
     fixed_cubes = fix_metadata(era5_cubes, var, 'native6', 'era5', mip)
+
     assert len(fixed_cubes) == 1
     fixed_cube = fixed_cubes[0]
     cmor_cube = cmor_cubes[0]
+
+    # Test that CMOR checks are passing
+    fixed_cubes = cmor_check_metadata(fixed_cube, 'native6', mip, var)
+
     if fixed_cube.coords('time'):
         for cube in [fixed_cube, cmor_cube]:
             coord = cube.coord('time')
diff --git a/tests/integration/cmor/_fixes/obs4mips/test_airs_2_1.py b/tests/integration/cmor/_fixes/obs4mips/test_airs_2_1.py
index 4ac2ce7f2..80ce0d00c 100644
--- a/tests/integration/cmor/_fixes/obs4mips/test_airs_2_1.py
+++ b/tests/integration/cmor/_fixes/obs4mips/test_airs_2_1.py
@@ -3,6 +3,7 @@ import numpy as np
 from iris.coords import DimCoord
 from iris.cube import Cube, CubeList
 
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor._fixes.obs4mips.airs_2_1 import AllVars
 from esmvalcore.cmor.fix import Fix
 
@@ -16,7 +17,7 @@ def get_air_pressure_coord(points, units):
 def test_get_allvars_fix():
     """Test getting of fix."""
     fix = Fix.get_fixes('obs4MIPs', 'AIRS-2-1', 'Amon', 'cl')
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_allvars_fix_no_air_pressure():
diff --git a/tests/integration/cmor/_fixes/obs4mips/test_ssmi.py b/tests/integration/cmor/_fixes/obs4mips/test_ssmi.py
index bde17735c..6a6648677 100644
--- a/tests/integration/cmor/_fixes/obs4mips/test_ssmi.py
+++ b/tests/integration/cmor/_fixes/obs4mips/test_ssmi.py
@@ -1,6 +1,7 @@
 """Test SSMI fixes."""
 import unittest
 
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor._fixes.obs4mips.ssmi import Prw
 from esmvalcore.cmor.fix import Fix
 
@@ -10,4 +11,4 @@ class TestPrw(unittest.TestCase):
     def test_get(self):
         """Test fix get."""
         self.assertListEqual(Fix.get_fixes('obs4MIPs', 'SSMI', 'Amon', 'prw'),
-                             [Prw(None)])
+                             [Prw(None), GenericFix(None)])
diff --git a/tests/integration/cmor/_fixes/obs4mips/test_ssmi_meris.py b/tests/integration/cmor/_fixes/obs4mips/test_ssmi_meris.py
index 47ec98b12..024aa4e70 100644
--- a/tests/integration/cmor/_fixes/obs4mips/test_ssmi_meris.py
+++ b/tests/integration/cmor/_fixes/obs4mips/test_ssmi_meris.py
@@ -1,6 +1,7 @@
 """Test SSMI fixes."""
 import unittest
 
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor._fixes.obs4mips.ssmi_meris import Prw
 from esmvalcore.cmor.fix import Fix
 
@@ -11,4 +12,4 @@ class TestPrw(unittest.TestCase):
         """Test fix get."""
         self.assertListEqual(
             Fix.get_fixes('obs4MIPs', 'SSMI-MERIS', 'Amon', 'prw'),
-            [Prw(None)])
+            [Prw(None), GenericFix(None)])
diff --git a/tests/integration/cmor/_fixes/test_fix.py b/tests/integration/cmor/_fixes/test_fix.py
index 7abc73418..ea4ecec14 100644
--- a/tests/integration/cmor/_fixes/test_fix.py
+++ b/tests/integration/cmor/_fixes/test_fix.py
@@ -14,16 +14,22 @@ from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5.cnrm_aladin63 import (
     Tas,
 )
 from esmvalcore.cmor._fixes.cordex.cordex_fixes import AllVars
+from esmvalcore.cmor._fixes.fix import GenericFix
 from esmvalcore.cmor.fix import Fix
+from esmvalcore.cmor.table import get_var_info
 from esmvalcore.config import CFG
 
 
 def test_get_fix():
-    assert Fix.get_fixes('CMIP5', 'CanESM2', 'Amon', 'fgco2') == [FgCo2(None)]
+    assert Fix.get_fixes('CMIP5', 'CanESM2', 'Amon', 'fgco2') == [
+        FgCo2(None), GenericFix(None)
+    ]
 
 
 def test_get_fix_case_insensitive():
-    assert Fix.get_fixes('CMIP5', 'CanESM2', 'Amon', 'fgCo2'), [FgCo2(None)]
+    assert Fix.get_fixes('CMIP5', 'CanESM2', 'Amon', 'fgCo2') == [
+        FgCo2(None), GenericFix(None)
+    ]
 
 
 def test_get_fix_cordex():
@@ -34,7 +40,7 @@ def test_get_fix_cordex():
         'tas',
         extra_facets={'driver': 'CNRM-CERFACS-CNRM-CM5'},
     )
-    assert fix == [Tas(None), AllVars(None)]
+    assert fix == [Tas(None), AllVars(None), GenericFix(None)]
 
 
 def test_get_grid_fix_cordex():
@@ -45,15 +51,19 @@ def test_get_grid_fix_cordex():
         'tas',
         extra_facets={'driver': 'CNRM-CERFACS-CNRM-CM5'},
     )
-    assert fix == [AllVars(None)]
+    assert fix == [AllVars(None), GenericFix(None)]
 
 
 def test_get_fixes_with_replace():
-    assert Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'ch4') == [Ch4(None)]
+    assert Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'ch4') == [
+        Ch4(None), GenericFix(None)
+    ]
 
 
 def test_get_fixes_with_generic():
-    assert Fix.get_fixes('CMIP5', 'CESM1-BGC', 'Amon', 'gpp') == [Gpp(None)]
+    assert Fix.get_fixes('CMIP5', 'CESM1-BGC', 'Amon', 'gpp') == [
+        Gpp(None), GenericFix(None)
+    ]
 
 
 def test_get_fix_no_project():
@@ -62,24 +72,33 @@ def test_get_fix_no_project():
 
 
 def test_get_fix_no_model():
-    assert Fix.get_fixes('CMIP5', 'BAD_MODEL', 'Amon', 'ch4') == []
+    assert Fix.get_fixes('CMIP5', 'BAD_MODEL', 'Amon', 'ch4') == [
+        GenericFix(None)
+    ]
 
 
 def test_get_fix_no_var():
-    assert Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'BAD_VAR') == []
+    assert Fix.get_fixes('CMIP5', 'BNU-ESM', 'Amon', 'BAD_VAR') == [
+        GenericFix(None)
+    ]
 
 
 def test_get_fix_only_mip():
-    assert Fix.get_fixes('CMIP6', 'CESM2', 'Omon', 'thetao') == [Omon(None)]
+    assert Fix.get_fixes('CMIP6', 'CESM2', 'Omon', 'thetao') == [
+        Omon(None), GenericFix(None)
+    ]
 
 
 def test_get_fix_only_mip_case_insensitive():
-    assert Fix.get_fixes('CMIP6', 'CESM2', 'omOn', 'thetao') == [Omon(None)]
+    assert Fix.get_fixes('CMIP6', 'CESM2', 'omOn', 'thetao') == [
+        Omon(None), GenericFix(None)
+    ]
 
 
 def test_get_fix_mip_and_var():
-    assert (Fix.get_fixes('CMIP6', 'CESM2', 'Omon', 'tos') ==
-            [Tos(None), Omon(None)])
+    assert Fix.get_fixes('CMIP6', 'CESM2', 'Omon', 'tos') == [
+        Tos(None), Omon(None), GenericFix(None)
+    ]
 
 
 def test_fix_metadata():
@@ -156,3 +175,25 @@ def test_session():
     session = CFG.start_session('my session')
     fix = Fix(None, session=session)
     assert fix.session == session
+
+
+def test_frequency_empty():
+    fix = Fix(None)
+    assert fix.frequency is None
+
+
+def test_frequency_from_vardef():
+    vardef = get_var_info('CMIP6', 'Amon', 'tas')
+    fix = Fix(vardef)
+    assert fix.frequency == 'mon'
+
+
+def test_frequency_given():
+    fix = Fix(None, frequency='1hr')
+    assert fix.frequency == '1hr'
+
+
+def test_frequency_not_from_vardef():
+    vardef = get_var_info('CMIP6', 'Amon', 'tas')
+    fix = Fix(vardef, frequency='3hr')
+    assert fix.frequency == '3hr'
diff --git a/tests/integration/cmor/test_fix.py b/tests/integration/cmor/test_fix.py
new file mode 100644
index 000000000..e52dc0fd4
--- /dev/null
+++ b/tests/integration/cmor/test_fix.py
@@ -0,0 +1,909 @@
+"""Integration tests for fixes."""
+
+import dask.array as da
+import numpy as np
+import pytest
+from cf_units import Unit
+from iris.aux_factory import HybridHeightFactory, HybridPressureFactory
+from iris.coords import AuxCoord, DimCoord
+from iris.cube import Cube, CubeList
+
+from esmvalcore.cmor.check import CheckLevels, CMORCheckError
+from esmvalcore.exceptions import ESMValCoreDeprecationWarning
+from esmvalcore.preprocessor import (
+    cmor_check_data,
+    cmor_check_metadata,
+    fix_data,
+    fix_metadata,
+)
+
+
+# TODO: remove in v2.12
+@pytest.fixture(autouse=True)
+def disable_fix_cmor_checker(mocker):
+    """Disable the CMOR checker in fixes (will be default in v2.12)."""
+    class MockChecker:
+
+        def __init__(self, cube):
+            self._cube = cube
+
+        def check_metadata(self):
+            return self._cube
+
+        def check_data(self):
+            return self._cube
+
+    mock = mocker.patch('esmvalcore.cmor.fix._get_cmor_checker')
+    mock.return_value = MockChecker
+
+
+class TestGenericFix:
+    """Tests for ``GenericFix``."""
+
+    @pytest.fixture(autouse=True)
+    def setup(self, mocker):
+        """Setup tests."""
+        self.mock_debug = mocker.patch(
+            'esmvalcore.cmor._fixes.fix.GenericFix._debug_msg', autospec=True
+        )
+        self.mock_warning = mocker.patch(
+            'esmvalcore.cmor._fixes.fix.GenericFix._warning_msg',
+            autospec=True,
+        )
+
+        # Create sample data with CMOR errors
+        time_coord = DimCoord(
+            [15, 45],
+            standard_name='time',
+            var_name='time',
+            units=Unit('days since 1851-01-01', calendar='noleap'),
+            attributes={'test': 1, 'time_origin': 'will_be_removed'},
+        )
+        plev_coord_rev = DimCoord(
+            [250, 500, 850],
+            standard_name='air_pressure',
+            var_name='plev',
+            units='hPa',
+        )
+        lev_coord_hybrid_height = DimCoord(
+            [1.0, 0.5, 0.0],
+            standard_name='atmosphere_hybrid_height_coordinate',
+            var_name='lev',
+            units='m',
+        )
+        lev_coord_hybrid_pressure = DimCoord(
+            [0.0, 0.5, 1.0],
+            standard_name='atmosphere_hybrid_sigma_pressure_coordinate',
+            var_name='lev',
+            units='1',
+        )
+        ap_coord = AuxCoord(
+            [0.0, 0.0, 0.0],
+            var_name='ap',
+            units='Pa',
+        )
+        b_coord = AuxCoord(
+            [0.0, 0.5, 1.0],
+            var_name='b',
+            units='1',
+        )
+        ps_coord = AuxCoord(
+            np.full((2, 2, 2), 10),
+            var_name='ps',
+            units='Pa',
+        )
+        orog_coord = AuxCoord(
+            np.full((2, 2), 10),
+            var_name='orog',
+            units='m',
+        )
+        hybrid_height_factory = HybridHeightFactory(
+            delta=lev_coord_hybrid_height,
+            sigma=b_coord,
+            orography=orog_coord,
+        )
+        hybrid_pressure_factory = HybridPressureFactory(
+            delta=ap_coord,
+            sigma=lev_coord_hybrid_pressure,
+            surface_air_pressure=ps_coord,
+        )
+        lat_coord = DimCoord(
+            [0, 10],
+            standard_name='latitude',
+            var_name='lat',
+            units='degrees',
+        )
+        lat_coord_rev = DimCoord(
+            [10, -10],
+            standard_name='latitude',
+            var_name='lat',
+            units='degrees',
+        )
+        lat_coord_2d = AuxCoord(
+            [[10, -10]],
+            standard_name='latitude',
+            var_name='wrong_name',
+            units='degrees',
+        )
+        lon_coord = DimCoord(
+            [-180, 0],
+            standard_name='longitude',
+            var_name='lon',
+            units='degrees',
+        )
+        lon_coord_unstructured = AuxCoord(
+            [-180, 0],
+            bounds=[[-200, -180, -160], [-20, 0, 20]],
+            standard_name='longitude',
+            var_name='lon',
+            units='degrees',
+        )
+        lon_coord_2d = AuxCoord(
+            [[370, 380]],
+            standard_name='longitude',
+            var_name='wrong_name',
+            units='degrees',
+        )
+        height2m_coord = AuxCoord(
+            2.0,
+            standard_name='height',
+            var_name='height',
+            units='m',
+        )
+
+        coord_spec_3d = [
+            (time_coord, 0),
+            (lat_coord, 1),
+            (lon_coord, 2),
+        ]
+        self.cube_3d = Cube(
+            da.arange(2 * 2 * 2, dtype=np.float32).reshape(2, 2, 2),
+            standard_name='air_pressure',
+            long_name='Air Pressure',
+            var_name='tas',
+            units='celsius',
+            dim_coords_and_dims=coord_spec_3d,
+            aux_coords_and_dims=[(height2m_coord, ())],
+            attributes={},
+        )
+
+        coord_spec_4d = [
+            (time_coord, 0),
+            (plev_coord_rev, 1),
+            (lat_coord_rev, 2),
+            (lon_coord, 3),
+        ]
+        cube_4d = Cube(
+            da.arange(2 * 3 * 2 * 2, dtype=np.float32).reshape(2, 3, 2, 2),
+            standard_name='air_pressure',
+            long_name='Air Pressure',
+            var_name='ta',
+            units='celsius',
+            dim_coords_and_dims=coord_spec_4d,
+            attributes={},
+        )
+        self.cubes_4d = CubeList([cube_4d])
+
+        coord_spec_hybrid_height_4d = [
+            (time_coord, 0),
+            (lev_coord_hybrid_height, 1),
+            (lat_coord_rev, 2),
+            (lon_coord, 3),
+        ]
+        aux_coord_spec_hybrid_height_4d = [
+            (b_coord, 1),
+            (orog_coord, (2, 3)),
+        ]
+        cube_hybrid_height_4d = Cube(
+            da.arange(2 * 3 * 2 * 2, dtype=np.float32).reshape(2, 3, 2, 2),
+            standard_name='air_pressure',
+            long_name='Air Pressure',
+            var_name='ta',
+            units='celsius',
+            dim_coords_and_dims=coord_spec_hybrid_height_4d,
+            aux_coords_and_dims=aux_coord_spec_hybrid_height_4d,
+            aux_factories=[hybrid_height_factory],
+            attributes={},
+        )
+        self.cubes_hybrid_height_4d = CubeList([cube_hybrid_height_4d])
+
+        coord_spec_hybrid_pressure_4d = [
+            (time_coord, 0),
+            (lev_coord_hybrid_pressure, 1),
+            (lat_coord_rev, 2),
+            (lon_coord, 3),
+        ]
+        aux_coord_spec_hybrid_pressure_4d = [
+            (ap_coord, 1),
+            (ps_coord, (0, 2, 3)),
+        ]
+        cube_hybrid_pressure_4d = Cube(
+            da.arange(2 * 3 * 2 * 2, dtype=np.float32).reshape(2, 3, 2, 2),
+            standard_name='air_pressure',
+            long_name='Air Pressure',
+            var_name='ta',
+            units='celsius',
+            dim_coords_and_dims=coord_spec_hybrid_pressure_4d,
+            aux_coords_and_dims=aux_coord_spec_hybrid_pressure_4d,
+            aux_factories=[hybrid_pressure_factory],
+            attributes={},
+        )
+        self.cubes_hybrid_pressure_4d = CubeList([cube_hybrid_pressure_4d])
+
+        coord_spec_unstrucutred = [
+            (height2m_coord, ()),
+            (lat_coord_rev, 1),
+            (lon_coord_unstructured, 1),
+        ]
+        cube_unstructured = Cube(
+            da.zeros((2, 2)),
+            standard_name='air_pressure',
+            long_name='Air Pressure',
+            var_name='tas',
+            units='celsius',
+            dim_coords_and_dims=[(time_coord, 0)],
+            aux_coords_and_dims=coord_spec_unstrucutred,
+            attributes={},
+        )
+        self.cubes_unstructured = CubeList([cube_unstructured])
+
+        coord_spec_2d = [
+            (height2m_coord, ()),
+            (lat_coord_2d, (1, 2)),
+            (lon_coord_2d, (1, 2)),
+        ]
+        cube_2d_latlon = Cube(
+            da.zeros((2, 1, 2)),
+            standard_name='air_pressure',
+            long_name='Air Pressure',
+            var_name='tas',
+            units='celsius',
+            dim_coords_and_dims=[(time_coord, 0)],
+            aux_coords_and_dims=coord_spec_2d,
+            attributes={},
+        )
+        self.cubes_2d_latlon = CubeList([cube_2d_latlon])
+
+    def assert_time_metadata(self, cube):
+        """Assert time metadata is correct."""
+        assert cube.coord('time').standard_name == 'time'
+        assert cube.coord('time').var_name == 'time'
+        assert cube.coord('time').units == Unit(
+            'days since 1850-01-01', calendar='365_day'
+        )
+        assert cube.coord('time').attributes == {'test': 1}
+
+    def assert_time_data(self, cube, time_has_bounds=True):
+        """Assert time data is correct."""
+        np.testing.assert_allclose(cube.coord('time').points, [380, 410])
+        if time_has_bounds:
+            np.testing.assert_allclose(
+                cube.coord('time').bounds, [[365, 396], [396, 424]],
+            )
+        else:
+            assert cube.coord('time').bounds is None
+
+    def assert_plev_metadata(self, cube):
+        """Assert plev metadata is correct."""
+        assert cube.coord('air_pressure').standard_name == 'air_pressure'
+        assert cube.coord('air_pressure').var_name == 'plev'
+        assert cube.coord('air_pressure').units == 'Pa'
+        assert cube.coord('air_pressure').attributes == {}
+
+    def assert_lat_metadata(self, cube):
+        """Assert lat metadata is correct."""
+        assert cube.coord('latitude').standard_name == 'latitude'
+        assert cube.coord('latitude').var_name == 'lat'
+        assert str(cube.coord('latitude').units) == 'degrees_north'
+        assert cube.coord('latitude').attributes == {}
+
+    def assert_lon_metadata(self, cube):
+        """Assert lon metadata is correct."""
+        assert cube.coord('longitude').standard_name == 'longitude'
+        assert cube.coord('longitude').var_name == 'lon'
+        assert str(cube.coord('longitude').units) == 'degrees_east'
+        assert cube.coord('longitude').attributes == {}
+
+    def assert_ta_metadata(self, cube):
+        """Assert ta metadata is correct."""
+        # Variable metadata
+        assert cube.standard_name == 'air_temperature'
+        assert cube.long_name == 'Air Temperature'
+        assert cube.var_name == 'ta'
+        assert cube.units == 'K'
+        assert cube.attributes == {}
+
+    def assert_ta_data(self, cube, time_has_bounds=True):
+        """Assert ta data is correct."""
+        assert cube.has_lazy_data()
+        np.testing.assert_allclose(
+            cube.data,
+            [[[[284.15, 283.15],
+               [282.15, 281.15]],
+              [[280.15, 279.15],
+               [278.15, 277.15]],
+              [[276.15, 275.15],
+               [274.15, 273.15]]],
+             [[[296.15, 295.15],
+               [294.15, 293.15]],
+              [[292.15, 291.15],
+               [290.15, 289.15]],
+              [[288.15, 287.15],
+               [286.15, 285.15]]]],
+        )
+
+        # Time
+        self.assert_time_data(cube, time_has_bounds=time_has_bounds)
+
+        # Air pressure
+        np.testing.assert_allclose(
+            cube.coord('air_pressure').points,
+            [85000.0, 50000.0, 25000.0],
+            atol=1e-8,
+        )
+        assert cube.coord('air_pressure').bounds is None
+
+        # Latitude
+        np.testing.assert_allclose(
+            cube.coord('latitude').points, [-10.0, 10.0]
+        )
+        np.testing.assert_allclose(
+            cube.coord('latitude').bounds, [[-20.0, 0.0], [0.0, 20.0]]
+        )
+
+        # Longitude
+        np.testing.assert_allclose(
+            cube.coord('longitude').points, [0.0, 180.0]
+        )
+        np.testing.assert_allclose(
+            cube.coord('longitude').bounds, [[-90.0, 90.0], [90.0, 270.0]]
+        )
+
+    def assert_tas_metadata(self, cube):
+        """Assert tas metadata is correct."""
+        assert cube.standard_name == 'air_temperature'
+        assert cube.long_name == 'Near-Surface Air Temperature'
+        assert cube.var_name == 'tas'
+        assert cube.units == 'K'
+        assert cube.attributes == {}
+
+        # Height 2m coordinate
+        assert cube.coord('height').standard_name == 'height'
+        assert cube.coord('height').var_name == 'height'
+        assert cube.coord('height').units == 'm'
+        assert cube.coord('height').attributes == {}
+        np.testing.assert_allclose(cube.coord('height').points, 2.0)
+        assert cube.coord('height').bounds is None
+
+    def test_fix_metadata_amon_ta(self):
+        """Test ``fix_metadata``."""
+        short_name = 'ta'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'Amon'
+
+        fixed_cubes = fix_metadata(
+            self.cubes_4d,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_ta_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_plev_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+        self.assert_ta_data(fixed_cube)
+
+        cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 3
+        assert self.mock_warning.call_count == 9
+
+    def test_fix_metadata_amon_ta_wrong_lat_units(self):
+        """Test ``fix_metadata``."""
+        short_name = 'ta'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'Amon'
+
+        # Change units of latitude
+        self.cubes_4d[0].coord('latitude').units = 'K'
+
+        fixed_cubes = fix_metadata(
+            self.cubes_4d,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_ta_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_plev_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+        self.assert_ta_data(fixed_cube)
+
+        # CMOR check will fail because of wrong latitude units
+        assert fixed_cube.coord('latitude').units == 'K'
+        with pytest.raises(CMORCheckError):
+            cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        print(self.mock_debug.mock_calls)
+        print(self.mock_warning.mock_calls)
+
+        assert self.mock_debug.call_count == 3
+        assert self.mock_warning.call_count == 9
+
+    def test_fix_metadata_cfmon_ta_hybrid_height(self):
+        """Test ``fix_metadata`` with hybrid height coordinate."""
+        short_name = 'ta'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'CFmon'
+
+        fixed_cubes = fix_metadata(
+            self.cubes_hybrid_height_4d,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        hybrid_coord = fixed_cube.coord('atmosphere_hybrid_height_coordinate')
+        assert hybrid_coord.var_name == 'lev'
+        assert hybrid_coord.long_name is None
+        assert hybrid_coord.units == 'm'
+        np.testing.assert_allclose(hybrid_coord.points, [0.0, 0.5, 1.0])
+        assert fixed_cube.coords('altitude')
+        assert fixed_cube.coord_dims('altitude') == (1, 2, 3)
+
+        self.assert_ta_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+
+        cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 4
+        assert self.mock_warning.call_count == 9
+
+    def test_fix_metadata_cfmon_ta_hybrid_pressure(self):
+        """Test ``fix_metadata`` with hybrid pressure coordinate."""
+        short_name = 'ta'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'CFmon'
+
+        fixed_cubes = fix_metadata(
+            self.cubes_hybrid_pressure_4d,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        hybrid_coord = fixed_cube.coord(
+            'atmosphere_hybrid_sigma_pressure_coordinate'
+        )
+        assert hybrid_coord.var_name == 'lev'
+        assert hybrid_coord.long_name is None
+        assert hybrid_coord.units == '1'
+        np.testing.assert_allclose(hybrid_coord.points, [1.0, 0.5, 0.0])
+        assert fixed_cube.coords('air_pressure')
+        assert fixed_cube.coord_dims('air_pressure') == (0, 1, 2, 3)
+
+        self.assert_ta_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+
+        cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 4
+        assert self.mock_warning.call_count == 9
+
+    def test_fix_metadata_cfmon_ta_alternative(self):
+        """Test ``fix_metadata`` with alternative generic level coordinate."""
+        short_name = 'ta'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'CFmon'
+
+        fixed_cubes = fix_metadata(
+            self.cubes_4d,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_ta_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_plev_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+        self.assert_ta_data(fixed_cube)
+
+        cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 4
+        assert self.mock_warning.call_count == 9
+
+    def test_fix_metadata_cfmon_ta_no_alternative(self, mocker):
+        """Test ``fix_metadata`` with  no alternative coordinate."""
+        short_name = 'ta'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'CFmon'
+
+        # Remove alternative coordinate
+        self.cubes_4d[0].remove_coord('air_pressure')
+
+        fixed_cubes = fix_metadata(
+            self.cubes_4d,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_ta_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_time_data(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+
+        # CMOR check will fail because of missing alevel coordinate
+        assert not fixed_cube.coords('air_pressure')
+        with pytest.raises(CMORCheckError):
+            cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 2
+        assert self.mock_warning.call_count == 8
+
+    def test_fix_metadata_e1hr_ta(self):
+        """Test ``fix_metadata`` with plev3."""
+        short_name = 'ta'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'E1hr'
+
+        # Slightly adapt plev to test fixing of requested levels
+        self.cubes_4d[0].coord('air_pressure').points = [
+            250.0 + 9e-8, 500.0 + 9e-8, 850.0 + 9e-8
+        ]
+
+        fixed_cubes = fix_metadata(
+            self.cubes_4d,
+            short_name,
+            project,
+            dataset,
+            mip,
+            frequency='mon',
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_ta_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_plev_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+        self.assert_ta_data(fixed_cube, time_has_bounds=False)
+
+        cmor_check_metadata(
+            fixed_cube, project, mip, short_name, frequency='mon'
+        )
+
+        assert self.mock_debug.call_count == 4
+        assert self.mock_warning.call_count == 8
+
+    def test_fix_metadata_amon_tas_unstructured(self):
+        """Test ``fix_metadata`` with unstructured grid."""
+        short_name = 'tas'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'Amon'
+
+        fixed_cubes = fix_metadata(
+            self.cubes_unstructured,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_tas_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+
+        # Latitude
+        np.testing.assert_allclose(
+            fixed_cube.coord('latitude').points, [10.0, -10.0]
+        )
+        assert fixed_cube.coord('latitude').bounds is None
+
+        # Longitude
+        np.testing.assert_allclose(
+            fixed_cube.coord('longitude').points, [180.0, 0.0]
+        )
+        np.testing.assert_allclose(
+            fixed_cube.coord('longitude').bounds,
+            [[160.0, 180.0, 200.0], [340.0, 0.0, 20.0]],
+        )
+
+        # Variable data
+        assert fixed_cube.has_lazy_data()
+        np.testing.assert_allclose(
+            fixed_cube.data, [[273.15, 273.15], [273.15, 273.15]]
+        )
+
+        cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 2
+        assert self.mock_warning.call_count == 6
+
+    def test_fix_metadata_amon_tas_2d_latlon(self):
+        """Test ``fix_metadata`` with 2D latitude/longitude."""
+        short_name = 'tas'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'Amon'
+
+        fixed_cubes = fix_metadata(
+            self.cubes_2d_latlon,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_tas_metadata(fixed_cube)
+        self.assert_time_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+
+        # Latitude
+        np.testing.assert_allclose(
+            fixed_cube.coord('latitude').points, [[10.0, -10.0]]
+        )
+        assert fixed_cube.coord('latitude').bounds is None
+
+        # Longitude
+        np.testing.assert_allclose(
+            fixed_cube.coord('longitude').points, [[10.0, 20.0]]
+        )
+        assert fixed_cube.coord('longitude').bounds is None
+
+        # Variable data
+        assert fixed_cube.has_lazy_data()
+        np.testing.assert_allclose(
+            fixed_cube.data, [[[273.15, 273.15]], [[273.15, 273.15]]]
+        )
+
+        cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 3
+        assert self.mock_warning.call_count == 8
+
+    def test_fix_metadata_amon_tas_invalid_time_units(self):
+        """Test ``fix_metadata`` with invalid time units."""
+        short_name = 'tas'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'Amon'
+
+        self.cubes_2d_latlon[0].remove_coord('time')
+        aux_time_coord = AuxCoord(
+            [1, 2],
+            standard_name='time',
+            var_name='time',
+            units='kg',
+        )
+        self.cubes_2d_latlon[0].add_aux_coord(aux_time_coord, 0)
+
+        fixed_cubes = fix_metadata(
+            self.cubes_2d_latlon,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+
+        assert fixed_cube.coord('time').units == 'kg'
+
+        # CMOR checks fail because calendar is not defined
+        with pytest.raises(ValueError):
+            cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 3
+        assert self.mock_warning.call_count == 7
+
+    def test_fix_metadata_amon_tas_invalid_time_attrs(self):
+        """Test ``fix_metadata`` with invalid time attributes."""
+        short_name = 'tas'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'Amon'
+
+        self.cubes_2d_latlon[0].attributes = {
+            'parent_time_units': 'this is certainly not a unit',
+            'branch_time_in_parent': 'BRANCH TIME IN PARENT',
+            'branch_time_in_child': 'BRANCH TIME IN CHILD',
+        }
+
+        fixed_cubes = fix_metadata(
+            self.cubes_2d_latlon,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        self.assert_time_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+
+        assert fixed_cube.attributes == {
+            'parent_time_units': 'this is certainly not a unit',
+            'branch_time_in_parent': 'BRANCH TIME IN PARENT',
+            'branch_time_in_child': 'BRANCH TIME IN CHILD',
+        }
+
+        cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 3
+        assert self.mock_warning.call_count == 8
+
+    def test_fix_metadata_oimon_ssi(self):
+        """Test ``fix_metadata`` with psu units."""
+        short_name = 'ssi'
+        project = 'CMIP5'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'OImon'
+
+        self.cubes_2d_latlon[0].var_name = 'ssi'
+        self.cubes_2d_latlon[0].attributes = {
+            'invalid_units': 'psu',
+            'parent_time_units': 'no parent',
+        }
+
+        # Also test 2D longitude that already has bounds
+        self.cubes_2d_latlon[0].coord('latitude').var_name = 'lat'
+        self.cubes_2d_latlon[0].coord('longitude').var_name = 'lon'
+        self.cubes_2d_latlon[0].coord('longitude').bounds = [
+            [[365.0, 375.0], [375.0, 400.0]]
+        ]
+
+        fixed_cubes = fix_metadata(
+            self.cubes_2d_latlon,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert len(fixed_cubes) == 1
+        fixed_cube = fixed_cubes[0]
+
+        # Variable metadata
+        assert fixed_cube.standard_name == 'sea_ice_salinity'
+        assert fixed_cube.long_name == 'Sea Ice Salinity'
+        assert fixed_cube.var_name == 'ssi'
+        assert fixed_cube.units == '1'
+        assert fixed_cube.attributes == {'parent_time_units': 'no parent'}
+
+        # Coordinates
+        self.assert_time_metadata(fixed_cube)
+        self.assert_lat_metadata(fixed_cube)
+        self.assert_lon_metadata(fixed_cube)
+
+        # Latitude
+        np.testing.assert_allclose(
+            fixed_cube.coord('latitude').points, [[10.0, -10.0]]
+        )
+        assert fixed_cube.coord('latitude').bounds is None
+
+        # Longitude
+        np.testing.assert_allclose(
+            fixed_cube.coord('longitude').points, [[10.0, 20.0]]
+        )
+        np.testing.assert_allclose(
+            fixed_cube.coord('longitude').bounds,
+            [[[5.0, 15.0], [15.0, 40.0]]],
+        )
+
+        # Variable data
+        assert fixed_cube.has_lazy_data()
+        np.testing.assert_allclose(
+            fixed_cube.data, [[[0.0, 0.0]], [[0.0, 0.0]]],
+        )
+
+        cmor_check_metadata(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 2
+        assert self.mock_warning.call_count == 6
+
+    def test_fix_data_amon_tas(self):
+        """Test ``fix_data``."""
+        short_name = 'tas'
+        project = 'CMIP6'
+        dataset = '__MODEL_WITH_NO_EXPLICIT_FIX__'
+        mip = 'Amon'
+
+        fixed_cube = fix_data(
+            self.cube_3d,
+            short_name,
+            project,
+            dataset,
+            mip,
+        )
+
+        assert fixed_cube.has_lazy_data()
+
+        cmor_check_data(fixed_cube, project, mip, short_name)
+
+        assert self.mock_debug.call_count == 0
+        assert self.mock_warning.call_count == 0
+
+    def test_deprecate_check_level_fix_metadata(self):
+        """Test deprecation of check level in ``fix_metadata``."""
+        with pytest.warns(ESMValCoreDeprecationWarning):
+            fix_metadata(
+                self.cubes_4d,
+                'ta',
+                'CMIP6',
+                'MODEL',
+                'Amon',
+                check_level=CheckLevels.RELAXED,
+            )
+
+    def test_deprecate_check_level_fix_data(self):
+        """Test deprecation of check level in ``fix_data``."""
+        with pytest.warns(ESMValCoreDeprecationWarning):
+            fix_metadata(
+                self.cubes_4d,
+                'ta',
+                'CMIP6',
+                'MODEL',
+                'Amon',
+                check_level=CheckLevels.RELAXED,
+            )
diff --git a/tests/integration/cmor/test_read_cmor_tables.py b/tests/integration/cmor/test_read_cmor_tables.py
index facb94f96..4a50e2c76 100644
--- a/tests/integration/cmor/test_read_cmor_tables.py
+++ b/tests/integration/cmor/test_read_cmor_tables.py
@@ -1,6 +1,5 @@
 from pathlib import Path
 
-import pytest
 import yaml
 
 from esmvalcore.cmor.table import CMOR_TABLES
@@ -45,15 +44,11 @@ def test_read_cmor_tables():
     assert table.strict is False
 
 
-@pytest.mark.parametrize('behaviour', ['current', 'deprecated'])
-def test_read_custom_cmor_tables(tmp_path, behaviour):
+def test_read_custom_cmor_tables(tmp_path):
     """Test reading of custom CMOR tables."""
     cfg_file = tmp_path / 'config-developer.yml'
-    if behaviour == 'deprecated':
-        cfg_file = CUSTOM_CFG_DEVELOPER
-    else:
-        with cfg_file.open('w', encoding='utf-8') as file:
-            yaml.safe_dump(CUSTOM_CFG_DEVELOPER, file)
+    with cfg_file.open('w', encoding='utf-8') as file:
+        yaml.safe_dump(CUSTOM_CFG_DEVELOPER, file)
 
     read_cmor_tables(cfg_file)
 
diff --git a/tests/integration/cmor/test_table.py b/tests/integration/cmor/test_table.py
index 7b25b8d71..8b8d63e57 100644
--- a/tests/integration/cmor/test_table.py
+++ b/tests/integration/cmor/test_table.py
@@ -3,6 +3,8 @@
 import os
 import unittest
 
+import pytest
+
 import esmvalcore.cmor
 from esmvalcore.cmor.table import (
     CMIP3Info,
@@ -10,6 +12,7 @@ from esmvalcore.cmor.table import (
     CMIP6Info,
     CustomInfo,
     _update_cmor_facets,
+    get_var_info,
 )
 
 
@@ -485,3 +488,41 @@ class TestCustomInfo(unittest.TestCase):
         self.assertEqual(var.long_name,
                          'Atmosphere CH4 surface')
         self.assertEqual(var.units, '1e-09')
+
+
+@pytest.mark.parametrize(
+    'project,mip,short_name,frequency',
+    [
+        ('CMIP5', 'Amon', 'tas', 'mon'),
+        ('CMIP5', 'day', 'tas', 'day'),
+        ('CMIP6', 'Amon', 'tas', 'mon'),
+        ('CMIP6', 'day', 'tas', 'day'),
+        ('CORDEX', '3hr', 'tas', '3hr'),
+    ]
+)
+def test_get_var_info(project, mip, short_name, frequency):
+    """Test ``get_var_info``."""
+    var_info = get_var_info(project, mip, short_name)
+
+    assert var_info.short_name == short_name
+    assert var_info.frequency == frequency
+
+
+@pytest.mark.parametrize(
+    'mip,short_name',
+    [
+        ('INVALID_MIP', 'tas'),
+        ('Amon', 'INVALID_VAR'),
+    ]
+)
+def test_get_var_info_invalid_mip_short_name(mip, short_name):
+    """Test ``get_var_info``."""
+    var_info = get_var_info('CMIP6', mip, short_name)
+
+    assert var_info is None
+
+
+def test_get_var_info_invalid_project():
+    """Test ``get_var_info``."""
+    with pytest.raises(KeyError):
+        get_var_info('INVALID_PROJECT', 'Amon', 'tas')
diff --git a/tests/integration/preprocessor/_io/test_load.py b/tests/integration/preprocessor/_io/test_load.py
index 99247bdc5..c0ad0bba8 100644
--- a/tests/integration/preprocessor/_io/test_load.py
+++ b/tests/integration/preprocessor/_io/test_load.py
@@ -10,7 +10,7 @@ import numpy as np
 from iris.coords import DimCoord
 from iris.cube import Cube, CubeList
 
-from esmvalcore.preprocessor._io import concatenate_callback, load
+from esmvalcore.preprocessor._io import load
 
 
 def _create_sample_cube():
@@ -60,7 +60,7 @@ class TestLoad(unittest.TestCase):
                 cube.attributes[attr] = attr
             self._save_cube(cube)
         for temp_file in self.temp_files:
-            cubes = load(temp_file, callback='default')
+            cubes = load(temp_file)
             cube = cubes[0]
             self.assertEqual(1, len(cubes))
             self.assertTrue((cube.data == np.array([1, 2])).all())
@@ -79,7 +79,7 @@ class TestLoad(unittest.TestCase):
                     coord.attributes[attr] = attr
             self._save_cube(cube)
         for temp_file in self.temp_files:
-            cubes = load(temp_file, callback='default')
+            cubes = load(temp_file)
             cube = cubes[0]
             self.assertEqual(1, len(cubes))
             self.assertTrue((cube.data == np.array([1, 2])).all())
@@ -94,7 +94,7 @@ class TestLoad(unittest.TestCase):
         cube = _create_sample_cube()
         temp_file = self._save_cube(cube)
 
-        cubes = load(temp_file, callback=concatenate_callback)
+        cubes = load(temp_file)
         cube = cubes[0]
         self.assertEqual(1, len(cubes))
         self.assertTrue((cube.data == np.array([1, 2])).all())
diff --git a/tests/integration/preprocessor/test_preprocessing_task.py b/tests/integration/preprocessor/test_preprocessing_task.py
index 81f980c9e..3b33e8f44 100644
--- a/tests/integration/preprocessor/test_preprocessing_task.py
+++ b/tests/integration/preprocessor/test_preprocessing_task.py
@@ -16,7 +16,7 @@ def test_load_save_task(tmp_path):
     iris.save(cube, in_file)
     dataset = Dataset(short_name='tas')
     dataset.files = [in_file]
-    dataset._load_with_callback = lambda _: cube.copy()
+    dataset.load = lambda: cube.copy()
 
     # Create task
     task = PreprocessingTask([
@@ -57,11 +57,11 @@ def test_load_save_and_other_task(tmp_path, monkeypatch):
 
     dataset1 = Dataset(short_name='tas', dataset='dataset1')
     dataset1.files = [file1]
-    dataset1._load_with_callback = lambda _: in_cube.copy()
+    dataset1.load = lambda: in_cube.copy()
 
     dataset2 = Dataset(short_name='tas', dataset='dataset1')
     dataset2.files = [file2]
-    dataset2._load_with_callback = lambda _: in_cube.copy()
+    dataset2.load = lambda: in_cube.copy()
 
     # Create some mock preprocessor functions and patch
     # `esmvalcore.preprocessor` so it uses them.
diff --git a/tests/integration/recipe/test_recipe.py b/tests/integration/recipe/test_recipe.py
index ba53388dd..6090e61c1 100644
--- a/tests/integration/recipe/test_recipe.py
+++ b/tests/integration/recipe/test_recipe.py
@@ -82,7 +82,6 @@ MANDATORY_SCRIPT_SETTINGS_KEYS = (
 )
 
 DEFAULT_PREPROCESSOR_STEPS = (
-    'load',
     'remove_supplementary_variables',
     'save',
 )
@@ -106,9 +105,6 @@ def create_test_file(filename, tracking_id=None):
 def _get_default_settings_for_chl(save_filename):
     """Get default preprocessor settings for chl."""
     defaults = {
-        'load': {
-            'callback': 'default'
-        },
         'remove_supplementary_variables': {},
         'save': {
             'compress': False,
@@ -557,9 +553,6 @@ def test_default_fx_preprocessor(tmp_path, patched_datafinder, session):
     assert preproc_dir.startswith(str(tmp_path))
 
     defaults = {
-        'load': {
-            'callback': 'default'
-        },
         'remove_supplementary_variables': {},
         'save': {
             'compress': False,
diff --git a/tests/unit/cmor/test_cmor_check.py b/tests/unit/cmor/test_cmor_check.py
index f3135558a..957136fd4 100644
--- a/tests/unit/cmor/test_cmor_check.py
+++ b/tests/unit/cmor/test_cmor_check.py
@@ -1,5 +1,6 @@
 """Unit tests for the CMORCheck class."""
 
+import logging
 import unittest
 from copy import deepcopy
 
@@ -10,6 +11,7 @@ import iris.coords
 import iris.cube
 import iris.util
 import numpy as np
+import pytest
 from cf_units import Unit
 
 from esmvalcore.cmor.check import (
@@ -18,6 +20,9 @@ from esmvalcore.cmor.check import (
     CMORCheckError,
     _get_cmor_checker,
 )
+from esmvalcore.exceptions import ESMValCoreDeprecationWarning
+
+logger = logging.getLogger(__name__)
 
 
 class VariableInfoMock:
@@ -142,33 +147,39 @@ class TestCMORCheck(unittest.TestCase):
         """Test checks succeeds for a good cube."""
         self._check_cube()
 
-    def _check_cube(self, automatic_fixes=False, frequency=None,
+    def _check_cube(self, frequency=None,
                     check_level=CheckLevels.DEFAULT):
-        """Apply checks and optionally automatic fixes to self.cube."""
+        """Apply checks to self.cube."""
         def checker(cube):
             return CMORCheck(
                 cube,
                 self.var_info,
-                automatic_fixes=automatic_fixes,
                 frequency=frequency,
                 check_level=check_level)
 
         self.cube = checker(self.cube).check_metadata()
         self.cube = checker(self.cube).check_data()
 
-    def _check_cube_metadata(self, automatic_fixes=False, frequency=None,
+    def _check_cube_metadata(self, frequency=None,
                              check_level=CheckLevels.DEFAULT):
-        """Apply checks and optionally automatic fixes to self.cube."""
+        """Apply checks to self.cube."""
         def checker(cube):
             return CMORCheck(
                 cube,
                 self.var_info,
-                automatic_fixes=automatic_fixes,
                 frequency=frequency,
                 check_level=check_level)
 
         self.cube = checker(self.cube).check_metadata()
 
+    def test_check_with_custom_logger(self):
+        """Test checks with custom logger."""
+        def checker(cube):
+            return CMORCheck(cube, self.var_info)
+
+        self.cube = checker(self.cube).check_metadata(logger=logger)
+        self.cube = checker(self.cube).check_data(logger=logger)
+
     def test_check_with_month_number(self):
         """Test checks succeeds for a good cube with month number."""
         iris.coord_categorisation.add_month_number(self.cube, 'time')
@@ -189,13 +200,6 @@ class TestCMORCheck(unittest.TestCase):
         iris.coord_categorisation.add_year(self.cube, 'time')
         self._check_cube()
 
-    def test_check_with_time_attributes(self):
-        """Test checks succeeds for a good cube with year."""
-        self.cube.coord('time').attributes['time_origin'] = "cow"
-        assert self.cube.coord('time').attributes['time_origin'] == "cow"
-        self._check_cube()
-        assert 'time_origin' not in self.cube.coord('time').attributes
-
     def test_check_no_multiple_coords_same_stdname(self):
         """Test checks fails if two coords have the same standard_name."""
         self.cube.add_aux_coord(
@@ -209,43 +213,20 @@ class TestCMORCheck(unittest.TestCase):
         )
         self._check_fails_in_metadata()
 
-    def test_check_bad_standard_name_auto_fix(self):
-        """Test check pass for a bad standard_name with automatic fixes."""
-        self.cube.standard_name = 'wind_speed'
-        self._check_cube(automatic_fixes=True)
-        self._check_cube()
-
     def test_check_bad_standard_name(self):
         """Test check fails for a bad short_name."""
         self.cube.standard_name = 'wind_speed'
-        self._check_fails_in_metadata(automatic_fixes=False)
-
-    def test_check_bad_long_name_auto_fix(self):
-        """Test check pass for a bad standard_name with automatic fixes."""
-        self.cube.long_name = 'bad_name'
-        self._check_cube(automatic_fixes=True)
-        self._check_cube()
-
-    def test_check_bad_long_name_auto_fix_report_warning(self):
-        """Test check pass for a bad standard_name with automatic fixes."""
-        self.cube.long_name = 'bad_name'
-        self._check_warnings_on_metadata(automatic_fixes=True)
+        self._check_fails_in_metadata()
 
     def test_check_bad_long_name(self):
         """Test check fails for a bad short_name."""
         self.cube.long_name = 'bad_name'
         self._check_fails_in_metadata()
 
-    def test_check_with_unit_conversion(self):
-        """Test check succeeds for a good cube requiring unit conversion."""
+    def test_check_bad_units(self):
+        """Test check fails for bad units."""
         self.cube.units = 'days'
-        self._check_cube()
-
-    def test_check_with_psu_units(self):
-        """Test check succeeds for a good cube with psu units."""
-        self.var_info.units = 'psu'
-        self.cube = self.get_cube(self.var_info)
-        self._check_cube(automatic_fixes=True)
+        self._check_fails_in_metadata()
 
     def test_check_with_positive(self):
         """Check variable with positive attribute."""
@@ -288,25 +269,6 @@ class TestCMORCheck(unittest.TestCase):
         self.cube = self._get_unstructed_grid_cube()
         self._check_cube()
 
-    def test_unstructured_grid_automatic_fixes(self):
-        """Check succeeds even if two required coordinates share dimensions."""
-        self.cube = self._get_unstructed_grid_cube(correct_lon=False,
-                                                   n_bounds=3)
-
-        lon_coord = self.cube.coord('longitude')
-        np.testing.assert_allclose(lon_coord.points.min(), -180.0)
-        np.testing.assert_allclose(lon_coord.points.max(), 162.0)
-        np.testing.assert_allclose(lon_coord.bounds.min(), -180.0)
-        np.testing.assert_allclose(lon_coord.bounds.max(), 171.0)
-
-        self._check_cube(automatic_fixes=True)
-
-        lon_coord = self.cube.coord('longitude')
-        np.testing.assert_allclose(lon_coord.points.min(), 0.0)
-        np.testing.assert_allclose(lon_coord.points.max(), 342.0)
-        np.testing.assert_allclose(lon_coord.bounds.min(), 0.0)
-        np.testing.assert_allclose(lon_coord.bounds.max(), 351.0)
-
     def test_bad_generic_level(self):
         """Test check fails in metadata if generic level coord
         has wrong var_name."""
@@ -328,6 +290,14 @@ class TestCMORCheck(unittest.TestCase):
         checker.check_metadata()
         checker.check_data()
 
+    # TODO: remove in v2.12
+    def test_valid_generic_level_automatic_fixes(self):
+        """Test valid generic level coordinate with automatic fixes."""
+        self._setup_generic_level_var()
+        checker = CMORCheck(self.cube, self.var_info, automatic_fixes=True)
+        checker.check_metadata()
+        checker.check_data()
+
     def test_invalid_generic_level(self):
         """Test invalid generic level coordinate."""
         self._setup_generic_level_var()
@@ -376,19 +346,19 @@ class TestCMORCheck(unittest.TestCase):
         """Test check fails for a bad variable standard_name with
         --cmor-check strict."""
         self.cube.standard_name = 'wind_speed'
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_bad_var_long_name_strict_flag(self):
         """Test check fails for a bad variable long_name with
         --cmor-check strict."""
         self.cube.long_name = "Near-Surface Wind Speed"
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_bad_var_units_strict_flag(self):
         """Test check fails for a bad variable units with
         --cmor-check strict."""
         self.cube.units = "kg"
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_bad_attributes_strict_flag(self):
         """Test check fails for a bad variable attribute with
@@ -397,7 +367,7 @@ class TestCMORCheck(unittest.TestCase):
         self.var_info.positive = "up"
         self.cube = self.get_cube(self.var_info)
         self.cube.attributes['positive'] = "Wrong attribute"
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_bad_rank_strict_flag(self):
         """Test check fails for a bad variable rank with
@@ -405,32 +375,32 @@ class TestCMORCheck(unittest.TestCase):
         lat = iris.coords.AuxCoord.from_coord(self.cube.coord('latitude'))
         self.cube.remove_coord('latitude')
         self.cube.add_aux_coord(lat, self.cube.coord_dims('longitude'))
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_bad_coord_var_name_strict_flag(self):
         """Test check fails for bad coord var_name with
         --cmor-check strict"""
         self.var_info.table_type = 'CMIP5'
         self.cube.coord('longitude').var_name = 'bad_name'
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_missing_lon_strict_flag(self):
         """Test check fails for missing longitude with --cmor-check strict"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('longitude')
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_missing_lat_strict_flag(self):
         """Test check fails for missing latitude with --cmor-check strict"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('latitude')
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_missing_time_strict_flag(self):
         """Test check fails for missing time with --cmor-check strict"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('time')
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_missing_coord_strict_flag(self):
         """Test check fails for missing coord other than lat and lon
@@ -438,28 +408,25 @@ class TestCMORCheck(unittest.TestCase):
         self.var_info.coordinates.update(
             {'height2m': CoordinateInfoMock('height2m')}
         )
-        self._check_fails_in_metadata(automatic_fixes=False)
+        self._check_fails_in_metadata()
 
     def test_check_bad_var_standard_name_relaxed_flag(self):
         """Test check reports warning for a bad variable standard_name with
         --cmor-check relaxed."""
         self.cube.standard_name = 'wind_speed'
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.RELAXED)
+        self._check_warnings_on_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_bad_var_long_name_relaxed_flag(self):
         """Test check reports warning for a bad variable long_name with
         --cmor-check relaxed."""
         self.cube.long_name = "Near-Surface Wind Speed"
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.RELAXED)
+        self._check_warnings_on_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_bad_var_units_relaxed_flag(self):
         """Test check reports warning for a bad variable units with
         --cmor-check relaxed."""
         self.cube.units = "kg"
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.RELAXED)
+        self._check_warnings_on_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_bad_attributes_relaxed_flag(self):
         """Test check report warnings for a bad variable attribute with
@@ -468,8 +435,7 @@ class TestCMORCheck(unittest.TestCase):
         self.var_info.positive = "up"
         self.cube = self.get_cube(self.var_info)
         self.cube.attributes['positive'] = "Wrong attribute"
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.RELAXED)
+        self._check_warnings_on_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_bad_rank_relaxed_flag(self):
         """Test check report warnings for a bad variable rank with
@@ -477,37 +443,32 @@ class TestCMORCheck(unittest.TestCase):
         lat = iris.coords.AuxCoord.from_coord(self.cube.coord('latitude'))
         self.cube.remove_coord('latitude')
         self.cube.add_aux_coord(lat, self.cube.coord_dims('longitude'))
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.RELAXED)
+        self._check_warnings_on_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_bad_coord_standard_name_relaxed_flag(self):
         """Test check reports warning for bad coord var_name with
         --cmor-check relaxed"""
         self.var_info.table_type = 'CMIP5'
         self.cube.coord('longitude').var_name = 'bad_name'
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.RELAXED)
+        self._check_warnings_on_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_missing_lon_relaxed_flag(self):
         """Test check fails for missing longitude with --cmor-check relaxed"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('longitude')
-        self._check_fails_in_metadata(automatic_fixes=False,
-                                      check_level=CheckLevels.RELAXED)
+        self._check_fails_in_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_missing_lat_relaxed_flag(self):
         """Test check fails for missing latitude with --cmor-check relaxed"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('latitude')
-        self._check_fails_in_metadata(automatic_fixes=False,
-                                      check_level=CheckLevels.RELAXED)
+        self._check_fails_in_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_missing_time_relaxed_flag(self):
         """Test check fails for missing latitude with --cmor-check relaxed"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('time')
-        self._check_fails_in_metadata(automatic_fixes=False,
-                                      check_level=CheckLevels.RELAXED)
+        self._check_fails_in_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_missing_coord_relaxed_flag(self):
         """Test check reports warning for missing coord other than lat and lon
@@ -515,29 +476,25 @@ class TestCMORCheck(unittest.TestCase):
         self.var_info.coordinates.update(
             {'height2m': CoordinateInfoMock('height2m')}
         )
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.RELAXED)
+        self._check_warnings_on_metadata(check_level=CheckLevels.RELAXED)
 
     def test_check_bad_var_standard_name_none_flag(self):
         """Test check reports warning for a bad variable standard_name with
         --cmor-check ignore."""
         self.cube.standard_name = 'wind_speed'
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_bad_var_long_name_none_flag(self):
         """Test check reports warning for a bad variable long_name with
         --cmor-check ignore."""
         self.cube.long_name = "Near-Surface Wind Speed"
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_bad_var_units_none_flag(self):
         """Test check reports warning for a bad variable unit with
         --cmor-check ignore."""
         self.cube.units = "kg"
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_bad_attributes_none_flag(self):
         """Test check reports warning for a bad variable attribute with
@@ -546,8 +503,7 @@ class TestCMORCheck(unittest.TestCase):
         self.var_info.positive = "up"
         self.cube = self.get_cube(self.var_info)
         self.cube.attributes['positive'] = "Wrong attribute"
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_bad_rank_none_flag(self):
         """Test check reports warning for a bad variable rank with
@@ -555,40 +511,35 @@ class TestCMORCheck(unittest.TestCase):
         lat = iris.coords.AuxCoord.from_coord(self.cube.coord('latitude'))
         self.cube.remove_coord('latitude')
         self.cube.add_aux_coord(lat, self.cube.coord_dims('longitude'))
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_bad_coord_standard_name_none_flag(self):
         """Test check reports warning for bad coord var_name with
         --cmor-check ignore."""
         self.var_info.table_type = 'CMIP5'
         self.cube.coord('longitude').var_name = 'bad_name'
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_missing_lon_none_flag(self):
         """Test check reports warning for missing longitude with
         --cmor-check ignore"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('longitude')
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_missing_lat_none_flag(self):
         """Test check reports warning for missing latitude with
         --cmor-check ignore"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('latitude')
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_missing_time_none_flag(self):
         """Test check reports warning for missing time
         with --cmor-check ignore"""
         self.var_info.table_type = 'CMIP5'
         self.cube.remove_coord('time')
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_missing_coord_none_flag(self):
         """Test check reports warning for missing coord other than lat, lon and
@@ -596,8 +547,7 @@ class TestCMORCheck(unittest.TestCase):
         self.var_info.coordinates.update(
             {'height2m': CoordinateInfoMock('height2m')}
         )
-        self._check_warnings_on_metadata(automatic_fixes=False,
-                                         check_level=CheckLevels.IGNORE)
+        self._check_warnings_on_metadata(check_level=CheckLevels.IGNORE)
 
     def test_check_lazy(self):
         """Test checker does not realise data or aux_coords."""
@@ -627,29 +577,28 @@ class TestCMORCheck(unittest.TestCase):
         self.assertTrue(self.cube.coord('longitude').has_lazy_points())
         self.assertTrue(self.cube.has_lazy_data())
 
-    def _check_fails_in_metadata(self, automatic_fixes=False, frequency=None,
+    def _check_fails_in_metadata(self, frequency=None,
                                  check_level=CheckLevels.DEFAULT):
         checker = CMORCheck(
             self.cube,
             self.var_info,
-            automatic_fixes=automatic_fixes,
             frequency=frequency,
-            check_level=check_level)
+            check_level=check_level,
+        )
         with self.assertRaises(CMORCheckError):
             checker.check_metadata()
 
-    def _check_warnings_on_metadata(self, automatic_fixes=False,
-                                    check_level=CheckLevels.DEFAULT):
+    def _check_warnings_on_metadata(self, check_level=CheckLevels.DEFAULT):
         checker = CMORCheck(
-            self.cube, self.var_info, automatic_fixes=automatic_fixes,
-            check_level=check_level
+            self.cube, self.var_info, check_level=check_level
         )
         checker.check_metadata()
         self.assertTrue(checker.has_warnings())
 
-    def _check_debug_messages_on_metadata(self, automatic_fixes=False):
+    def _check_debug_messages_on_metadata(self):
         checker = CMORCheck(
-            self.cube, self.var_info, automatic_fixes=automatic_fixes)
+            self.cube, self.var_info,
+        )
         checker.check_metadata()
         self.assertTrue(checker.has_debug_messages())
 
@@ -667,20 +616,6 @@ class TestCMORCheck(unittest.TestCase):
         checker.check_metadata()
         self.assertTrue(checker.has_warnings())
 
-    def test_almost_requested(self):
-        """Automatically fix tiny deviations from the requested values."""
-        coord = self.cube.coord('air_pressure')
-        values = np.array(coord.points)
-        values[0] += 1.e-7
-        values[-1] += 1.e-7
-        self._update_coordinate_values(self.cube, coord, values)
-        checker = CMORCheck(self.cube, self.var_info, automatic_fixes=True)
-        checker.check_metadata()
-        reference = np.array(
-            self.var_info.coordinates['air_pressure'].requested, dtype=float)
-        np.testing.assert_array_equal(
-            self.cube.coord('air_pressure').points, reference)
-
     def test_requested_str_values(self):
         """
         Warning if requested values are not present.
@@ -728,65 +663,40 @@ class TestCMORCheck(unittest.TestCase):
         self._update_coordinate_values(self.cube, coord, values)
         self._check_fails_in_metadata()
 
-    def test_non_increasing_fix(self):
-        """Check automatic fix for direction."""
-        coord = self.cube.coord('latitude')
-        values = np.linspace(
-            coord.points[-1],
-            coord.points[0],
-            len(coord.points)
-        )
-        self._update_coordinate_values(self.cube, coord, values)
-        self._check_cube(automatic_fixes=True)
-        self._check_cube()
-        # test bounds are contiguous
-        bounds = self.cube.coord('latitude').bounds
-        right_bounds = bounds[:-2, 1]
-        left_bounds = bounds[1:-1, 0]
-        self.assertTrue(np.all(left_bounds == right_bounds))
-
     def test_non_decreasing(self):
         """Fail in metadata if decreasing coordinate is increasing."""
         self.var_info.coordinates['lat'].stored_direction = 'decreasing'
         self._check_fails_in_metadata()
 
-    def test_non_decreasing_fix(self):
-        """Check automatic fix for non decreasing coordinate."""
-        self.cube.data[0, 0, 0, 0, 0] = 70
+    # TODO: remove in v2.12
+    def test_non_decreasing_automatic_fix_metadata(self):
+        """Automatic fix for decreasing coordinate."""
         self.var_info.coordinates['lat'].stored_direction = 'decreasing'
-        self._check_cube(automatic_fixes=True)
-        self._check_cube()
-        index = [0, 0, 0, 0, 0]
-        index[self.cube.coord_dims('latitude')[0]] = -1
-        self.assertEqual(self.cube.data.item(tuple(index)), 70)
-        self.assertEqual(self.cube.data[0, 0, 0, 0, 0], 50)
-        cube_points = self.cube.coord('latitude').points
-        reference = np.linspace(90, -90, 20, endpoint=True)
-        for index in range(20):
-            np.testing.assert_allclose(cube_points[index], reference[index])
-        # test bounds are contiguous
-        bounds = self.cube.coord('latitude').bounds
-        right_bounds = bounds[:-2, 1]
-        left_bounds = bounds[1:-1, 0]
-        self.assertTrue(np.all(left_bounds == right_bounds))
+        checker = CMORCheck(self.cube, self.var_info, automatic_fixes=True)
+        checker.check_metadata()
 
-    def test_not_bounds(self):
-        """Warning if bounds are not available."""
-        self.cube.coord('longitude').bounds = None
-        self._check_warnings_on_metadata(automatic_fixes=False)
-        self.assertFalse(self.cube.coord('longitude').has_bounds())
+    # TODO: remove in v2.12
+    def test_non_decreasing_automatic_fix_data(self):
+        """Automatic fix for decreasing coordinate."""
+        self.var_info.coordinates['lat'].stored_direction = 'decreasing'
+        checker = CMORCheck(self.cube, self.var_info, automatic_fixes=True)
+        checker.check_data()
 
-    def test_guess_bounds_with_fixes(self):
-        """Warning if bounds added with automatic fixes."""
-        self.cube.coord('longitude').bounds = None
-        self._check_warnings_on_metadata(automatic_fixes=True)
-        self.assertTrue(self.cube.coord('longitude').has_bounds())
+    def test_lat_non_monotonic(self):
+        """Test fail for non monotonic latitude."""
+        lat = self.cube.coord('latitude')
+        points = np.array(lat.points)
+        points[-1] = points[0]
+        dims = self.cube.coord_dims(lat)
+        self.cube.remove_coord(lat)
+        lat = iris.coords.AuxCoord.from_coord(lat)
+        self.cube.add_aux_coord(lat.copy(points), dims)
+        self._check_fails_in_metadata()
 
-    def test_not_guess_bounds_with_fixes(self):
-        """Warning if bounds added with automatic fixes."""
+    def test_not_bounds(self):
+        """Warning if bounds are not available."""
         self.cube.coord('longitude').bounds = None
-        self.var_info.coordinates['lon'].must_have_bounds = "no"
-        self._check_cube(automatic_fixes=True)
+        self._check_warnings_on_metadata()
         self.assertFalse(self.cube.coord('longitude').has_bounds())
 
     def test_not_correct_lons(self):
@@ -794,34 +704,15 @@ class TestCMORCheck(unittest.TestCase):
         self.cube = self.cube.intersection(longitude=(-180., 180.))
         self._check_fails_in_metadata()
 
-    def test_lons_automatic_fix(self):
-        """Test automatic fixes for bad longitudes."""
-        self.cube = self.cube.intersection(longitude=(-180., 180.))
-        self._check_cube(automatic_fixes=True)
-
-    def test_lons_automatic_fix_with_bounds(self):
-        """Test automatic fixes for bad longitudes with added bounds."""
-        self.cube.coord('longitude').bounds = None
-        self.cube = self.cube.intersection(longitude=(-180., 180.))
-        self._check_cube(automatic_fixes=True)
-        self.assertTrue(self.cube.coord('longitude').points.min() >= 0.)
-        self.assertTrue(self.cube.coord('longitude').points.max() <= 360.)
-        self.assertTrue(self.cube.coord('longitude').has_bounds())
-
-    def test_high_lons_automatic_fix(self):
-        """Test automatic fixes for high longitudes."""
-        self.cube = self.cube.intersection(longitude=(180., 520.))
-        self._check_cube(automatic_fixes=True)
-
-    def test_too_high_lons_automatic_fix_not_done(self):
-        """Test automatic fixes for bad longitudes."""
+    def test_high_lons(self):
+        """Test bad longitudes."""
         self.cube = self.cube.intersection(longitude=(720., 1080.))
-        self._check_fails_in_metadata(automatic_fixes=True)
+        self._check_fails_in_metadata()
 
-    def test_too_low_lons_automatic_fix_not_done(self):
-        """Test automatic fixes for bad longitudes."""
+    def test_low_lons(self):
+        """Test bad longitudes."""
         self.cube = self.cube.intersection(longitude=(-720., -360.))
-        self._check_fails_in_metadata(automatic_fixes=True)
+        self._check_fails_in_metadata()
 
     def test_not_valid_min(self):
         """Fail if coordinate values below valid_min."""
@@ -862,49 +753,16 @@ class TestCMORCheck(unittest.TestCase):
         self.cube.coord('latitude').units = 'degrees_n'
         self._check_fails_in_metadata()
 
-    def test_units_automatic_fix(self):
-        """Test automatic fix for bad coordinate units."""
-        self.cube.coord('latitude').units = 'degrees_n'
-        self._check_cube(automatic_fixes=True)
-
-    def test_units_automatic_fix_failed(self):
-        """Test automatic fix fail for incompatible coordinate units."""
+    def test_non_convertible_units(self):
+        """Test fail for incompatible coordinate units."""
         self.cube.coord('latitude').units = 'degC'
-        self._check_fails_in_metadata(automatic_fixes=True)
+        self._check_fails_in_metadata()
 
     def test_bad_time(self):
         """Fail if time have bad units."""
         self.cube.coord('time').units = 'days'
         self._check_fails_in_metadata()
 
-    def test_time_units_automatic_fix(self):
-        """Test automatic fix for time units."""
-        self.cube.coord('time').units = 'days since 1860-1-1 00:00:00'
-        self.cube.attributes['parent_time_units'] = 'days since ' \
-                                                    '1850-1-1 00:00:00'
-        self.cube.attributes['branch_time_in_parent'] = 0.
-        self.cube.attributes['branch_time_in_child'] = 0.
-        self._check_cube()
-        assert (self.cube.coord('time').units.origin ==
-                'days since 1850-1-1 00:00:00')
-        assert self.cube.attributes['parent_time_units'] == 'days since ' \
-                                                            '1850-1-1 00:00:00'
-        assert self.cube.attributes['branch_time_in_parent'] == 0.
-        assert self.cube.attributes['branch_time_in_child'] == 3652.
-
-    def test_time_units_no_parent_exp(self):
-        """Test non-conversion of time units attributes for no parent exps."""
-        self.cube.coord('time').units = 'days since 1860-1-1 00:00:00'
-        self.cube.attributes['parent_time_units'] = 'no parent'
-        self.cube.attributes['branch_time_in_parent'] = 0.
-        self.cube.attributes['branch_time_in_child'] = 0.
-        self._check_cube()
-        assert (self.cube.coord('time').units.origin ==
-                'days since 1850-1-1 00:00:00')
-        assert self.cube.attributes['parent_time_units'] == 'no parent'
-        assert self.cube.attributes['branch_time_in_parent'] == 0.
-        assert self.cube.attributes['branch_time_in_child'] == 0.
-
     def test_wrong_parent_time_unit(self):
         """Test fail for wrong parent time units."""
         self.cube.coord('time').units = 'days since 1860-1-1 00:00:00'
@@ -916,13 +774,13 @@ class TestCMORCheck(unittest.TestCase):
         assert self.cube.attributes['branch_time_in_parent'] == 0.
         assert self.cube.attributes['branch_time_in_child'] == 0
 
-    def test_time_automatic_fix_failed(self):
-        """Test automatic fix fail for incompatible time units."""
+    def test_time_non_time_units(self):
+        """Test fail for incompatible time units."""
         self.cube.coord('time').units = 'K'
-        self._check_fails_in_metadata(automatic_fixes=True)
+        self._check_fails_in_metadata()
 
     def test_time_non_monotonic(self):
-        """Test automatic fix fail for non monotonic times."""
+        """Test fail for non monotonic times."""
         time = self.cube.coord('time')
         points = np.array(time.points)
         points[-1] = points[0]
@@ -930,61 +788,13 @@ class TestCMORCheck(unittest.TestCase):
         self.cube.remove_coord(time)
         time = iris.coords.AuxCoord.from_coord(time)
         self.cube.add_aux_coord(time.copy(points), dims)
-        self._check_fails_in_metadata(automatic_fixes=True)
+        self._check_fails_in_metadata()
 
     def test_bad_standard_name(self):
         """Fail if coordinates have bad standard names at metadata step."""
         self.cube.coord('time').standard_name = 'region'
         self._check_fails_in_metadata()
 
-    def test_bad_out_name_multidim_latitude(self):
-        """Warning if multidimensional lat has bad var_name at metadata"""
-        self.var_info.table_type = 'CMIP6'
-        self.cube.remove_coord('latitude')
-        self.cube.add_aux_coord(
-            iris.coords.AuxCoord(
-                np.reshape(np.linspace(-90, 90, num=20*20), (20, 20)),
-                var_name='bad_name',
-                standard_name='latitude',
-                units='degrees_north'
-            ),
-            (1, 2)
-        )
-        self._check_debug_messages_on_metadata()
-
-    def test_bad_out_name_multidim_longitude(self):
-        """Warning if multidimensional lon has bad var_name at metadata"""
-        self.var_info.table_type = 'CMIP6'
-        self.cube.remove_coord('longitude')
-        self.cube.add_aux_coord(
-            iris.coords.AuxCoord(
-                np.reshape(np.linspace(-90, 90, num=20*20), (20, 20)),
-                var_name='bad_name',
-                standard_name='longitude',
-                units='degrees_east'
-            ),
-            (1, 2)
-        )
-        self._check_debug_messages_on_metadata(automatic_fixes=True)
-
-    def test_bad_bounds_in_multidim_longitude(self):
-        """Warning if multidimensional lon has bad var_name at metadata"""
-        self.var_info.table_type = 'CMIP6'
-        self.cube.remove_coord('longitude')
-        lons = np.reshape(np.linspace(180, 540, num=20*20), (20, 20))
-        bounds = np.stack([lons.copy() - 0.5, lons.copy() + 0.5], -1)
-        self.cube.add_aux_coord(
-            iris.coords.AuxCoord(
-                lons,
-                var_name='bad_name',
-                standard_name='longitude',
-                units='degrees_east',
-                bounds=bounds,
-            ),
-            (1, 2)
-        )
-        self._check_debug_messages_on_metadata(automatic_fixes=True)
-
     def test_bad_out_name_region_area_type(self):
         """Debug message if region/area_type AuxCoord has bad var_name at
         metadata."""
@@ -1086,49 +896,20 @@ class TestCMORCheck(unittest.TestCase):
         """Fail at metadata if frequency is not supported."""
         self._check_fails_in_metadata(frequency='wrong_freq')
 
-    def test_time_bounds(self):
-        """Test time bounds are guessed for all frequencies"""
-        freqs = ['hr', '3hr', '6hr', 'day', 'mon', 'yr', 'dec']
-        guessed = []
-        for freq in freqs:
-            cube = self.get_cube(self.var_info, frequency=freq)
-            cube.coord('time').bounds = None
-            self.cube = cube
-            self._check_cube(automatic_fixes=True, frequency=freq)
-            if cube.coord('time').bounds is not None:
-                guessed.append(True)
-        assert len(guessed) == len(freqs)
-
-    def test_no_time_bounds(self):
-        """Test time bounds are not guessed for instantaneous data"""
-        self.var_info.coordinates['time'].must_have_bounds = 'no'
-        self.var_info.coordinates['time1'] = (
-            self.var_info.coordinates.pop('time'))
-        self.cube.coord('time').bounds = None
-        self._check_cube(automatic_fixes=True)
-        guessed_bounds = self.cube.coord('time').bounds
-        assert guessed_bounds is None
-
     def test_hr_mip_cordex(self):
         """Test hourly CORDEX tables are found."""
         checker = _get_cmor_checker('CORDEX', '3hr', 'tas', '3hr')
         assert checker(self.cube)._cmor_var.short_name == 'tas'
         assert checker(self.cube)._cmor_var.frequency == '3hr'
 
-    def test_set_range_in_0_360(self):
-        checker = _get_cmor_checker('CMIP5', 'Amon', 'tas', 'mon')
-        arr_in = np.array([[-120.0, 0.0, 20.0], [-1.0, 360.0, 400.0]])
-        arr_exp = np.array([[240.0, 0.0, 20.0], [359.0, 0.0, 40.0]])
-        arr_out = checker(self.cube)._set_range_in_0_360(arr_in)
-        np.testing.assert_allclose(arr_out, arr_exp)
-
-    def test_set_range_in_0_360_lazy(self):
-        checker = _get_cmor_checker('CMIP5', 'Amon', 'tas', 'mon')
-        arr_in = da.from_array([[-120.0, 0.0, 20.0], [-1.0, 360.0, 400.0]])
-        arr_exp = da.from_array([[240.0, 0.0, 20.0], [359.0, 0.0, 40.0]])
-        arr_out = checker(self.cube)._set_range_in_0_360(arr_in)
-        self.assertTrue(isinstance(arr_out, da.core.Array))
-        np.testing.assert_allclose(arr_out.compute(), arr_exp.compute())
+    def test_custom_variable(self):
+        checker = _get_cmor_checker('OBS', 'Amon', 'uajet', 'mon')
+        assert checker(self.cube)._cmor_var.short_name == 'uajet'
+        assert checker(self.cube)._cmor_var.long_name == (
+            'Jet position expressed as latitude of maximum meridional wind '
+            'speed'
+        )
+        assert checker(self.cube)._cmor_var.units == 'degrees'
 
     def _check_fails_on_data(self):
         checker = CMORCheck(self.cube, self.var_info)
@@ -1210,7 +991,7 @@ class TestCMORCheck(unittest.TestCase):
 
         return cube
 
-    def _get_unstructed_grid_cube(self, correct_lon=True, n_bounds=2):
+    def _get_unstructed_grid_cube(self, n_bounds=2):
         """Get cube with unstructured grid."""
         assert n_bounds in (2, 3), "Only 2 or 3 bounds per cell supported"
 
@@ -1256,23 +1037,6 @@ class TestCMORCheck(unittest.TestCase):
                 ))
                 coord.bounds = np.swapaxes(new_bounds, 0, 1)
 
-        # Convert longitude to [-180, 180] to check automatic fixes if desired
-        if correct_lon:
-            return cube
-        new_lon = iris.coords.AuxCoord(
-            points=cube.coord('longitude').points,
-            bounds=cube.coord('longitude').bounds,
-            var_name='lon',
-            standard_name='longitude',
-            long_name='Longitude',
-            units='degrees_east',
-        )
-        new_lon.points = np.where(new_lon.points < 180.0, new_lon.points,
-                                  new_lon.points - 360.0)
-        new_lon.bounds = np.where(new_lon.bounds < 180.0, new_lon.bounds,
-                                  new_lon.bounds - 360.0)
-        cube.remove_coord('longitude')
-        cube.add_aux_coord(new_lon, 1)
         return cube
 
     def _setup_generic_level_var(self):
@@ -1450,5 +1214,17 @@ class TestCMORCheck(unittest.TestCase):
         return np.arange(start, end, step=delta)
 
 
+def test_get_cmor_checker_invalid_project_fail():
+    """Test ``_get_cmor_checker`` with invalid project."""
+    with pytest.raises(KeyError):
+        _get_cmor_checker('INVALID_PROJECT', 'mip', 'short_name', 'frequency')
+
+
+def test_deprecate_automatic_fixes():
+    """Test deprecation of automatic_fixes."""
+    with pytest.warns(ESMValCoreDeprecationWarning):
+        CMORCheck('cube', 'var_info', 'frequency', automatic_fixes=True)
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/unit/cmor/test_fix.py b/tests/unit/cmor/test_fix.py
index 86293e2aa..d6a06b2c1 100644
--- a/tests/unit/cmor/test_fix.py
+++ b/tests/unit/cmor/test_fix.py
@@ -1,16 +1,17 @@
 """Unit tests for :mod:`esmvalcore.cmor.fix`."""
 
 from pathlib import Path
-from unittest import TestCase
 from unittest.mock import Mock, patch, sentinel
 
-from esmvalcore.cmor.check import CheckLevels
+import pytest
+
 from esmvalcore.cmor.fix import Fix, fix_data, fix_file, fix_metadata
 
 
-class TestFixFile(TestCase):
+class TestFixFile():
     """Fix file tests."""
 
+    @pytest.fixture(autouse=True)
     def setUp(self):
         """Prepare for testing."""
         self.filename = 'filename'
@@ -26,8 +27,10 @@ class TestFixFile(TestCase):
                 'dataset': 'model',
                 'mip': 'mip',
                 'short_name': 'short_name',
+                'frequency': 'frequency',
             },
             'session': sentinel.session,
+            'frequency': 'frequency',
         }
 
     def test_fix(self):
@@ -42,9 +45,10 @@ class TestFixFile(TestCase):
                 mip='mip',
                 output_dir=Path('output_dir'),
                 session=sentinel.session,
+                frequency='frequency',
             )
-            self.assertNotEqual(file_returned, self.filename)
-            self.assertEqual(file_returned, 'new_filename')
+            assert file_returned != self.filename
+            assert file_returned == 'new_filename'
             mock_get_fixes.assert_called_once_with(
                 **self.expected_get_fixes_call
             )
@@ -61,16 +65,18 @@ class TestFixFile(TestCase):
                 mip='mip',
                 output_dir=Path('output_dir'),
                 session=sentinel.session,
+                frequency='frequency',
             )
-            self.assertEqual(file_returned, self.filename)
+            assert file_returned == self.filename
             mock_get_fixes.assert_called_once_with(
                 **self.expected_get_fixes_call
             )
 
 
-class TestGetCube(TestCase):
+class TestGetCube():
     """Test get cube by var_name method."""
 
+    @pytest.fixture(autouse=True)
     def setUp(self):
         """Prepare for testing."""
         self.cube_1 = Mock()
@@ -84,28 +90,27 @@ class TestGetCube(TestCase):
 
     def test_get_first_cube(self):
         """Test selecting first cube."""
-        self.assertIs(self.cube_1,
-                      self.fix.get_cube_from_list(self.cubes, "cube1"))
+        assert self.cube_1 is self.fix.get_cube_from_list(self.cubes, "cube1")
 
     def test_get_second_cube(self):
         """Test selecting second cube."""
-        self.assertIs(self.cube_2,
-                      self.fix.get_cube_from_list(self.cubes, "cube2"))
+        assert self.cube_2 is self.fix.get_cube_from_list(self.cubes, "cube2")
 
     def test_get_default_raises(self):
         """Check that the default raises (Fix is not a cube)."""
-        with self.assertRaises(Exception):
+        with pytest.raises(Exception):
             self.fix.get_cube_from_list(self.cubes)
 
     def test_get_default(self):
         """Check that the default return the cube (fix is a cube)."""
         self.cube_1.var_name = 'fix'
-        self.assertIs(self.cube_1, self.fix.get_cube_from_list(self.cubes))
+        assert self.cube_1 is self.fix.get_cube_from_list(self.cubes)
 
 
-class TestFixMetadata(TestCase):
+class TestFixMetadata():
     """Fix metadata tests."""
 
+    @pytest.fixture(autouse=True)
     def setUp(self):
         """Prepare for testing."""
         self.cube = self._create_mock_cube()
@@ -125,9 +130,10 @@ class TestFixMetadata(TestCase):
                 'dataset': 'model',
                 'mip': 'mip',
                 'short_name': 'short_name',
-                'frequency': None,
+                'frequency': 'frequency',
             },
             'session': sentinel.session,
+            'frequency': 'frequency',
         }
 
     @staticmethod
@@ -150,9 +156,12 @@ class TestFixMetadata(TestCase):
                     project='project',
                     dataset='model',
                     mip='mip',
+                    frequency='frequency',
                     session=sentinel.session,
                 )[0]
-                self.checker.assert_called_once_with(self.intermediate_cube)
+                self.checker.assert_called_once_with(
+                    self.intermediate_cube
+                )
                 self.check_metadata.assert_called_once_with()
                 assert cube_returned is not self.cube
                 assert cube_returned is not self.intermediate_cube
@@ -174,6 +183,7 @@ class TestFixMetadata(TestCase):
                     project='project',
                     dataset='model',
                     mip='mip',
+                    frequency='frequency',
                     session=sentinel.session,
                 )[0]
                 self.checker.assert_called_once_with(self.cube)
@@ -193,8 +203,7 @@ class TestFixMetadata(TestCase):
             with patch('esmvalcore.cmor.fix._get_cmor_checker',
                        return_value=self.checker):
                 cube_returned = fix_metadata(
-                    cubes=[self.cube,
-                           self._create_mock_cube('extra')],
+                    cubes=[self.cube, self._create_mock_cube('extra')],
                     short_name='short_name',
                     project='CMIP6',
                     dataset='model',
@@ -205,52 +214,25 @@ class TestFixMetadata(TestCase):
                 assert cube_returned is self.cube
 
     def test_select_var_failed_if_bad_var_name(self):
-        """Check that the same cube is returned if no fix is available."""
-        with patch('esmvalcore.cmor._fixes.fix.Fix.get_fixes',
-                   return_value=[]):
-            with self.assertRaises(ValueError):
-                fix_metadata(
-                    cubes=[
-                        self._create_mock_cube('not_me'),
-                        self._create_mock_cube('me_neither')
-                    ],
-                    short_name='short_name',
-                    project='CMIP6',
-                    dataset='model',
-                    mip='mip',
-                )
-
-    def test_cmor_checker_called(self):
-        """Check that the cmor check is done."""
-        checker = Mock()
-        checker.return_value = Mock()
-        with patch('esmvalcore.cmor._fixes.fix.Fix.get_fixes',
-                   return_value=[]):
-            with patch('esmvalcore.cmor.fix._get_cmor_checker',
-                       return_value=checker) as get_mock:
-                fix_metadata(
-                    cubes=[self.cube],
-                    short_name='short_name',
-                    project='CMIP6',
-                    dataset='dataset',
-                    mip='mip',
-                    frequency='frequency',
-                )
-                get_mock.assert_called_once_with(
-                    automatic_fixes=True,
-                    fail_on_error=False,
-                    frequency='frequency',
-                    mip='mip',
-                    short_name='short_name',
-                    table='CMIP6',
-                    check_level=CheckLevels.DEFAULT,)
-                checker.assert_called_once_with(self.cube)
-                checker.return_value.check_metadata.assert_called_once_with()
+        """Check that an error is raised if short_names do not match."""
+        msg = "More than one cube found for variable tas in CMIP6:model"
+        with pytest.raises(ValueError, match=msg):
+            fix_metadata(
+                cubes=[
+                    self._create_mock_cube('not_me'),
+                    self._create_mock_cube('me_neither')
+                ],
+                short_name='tas',
+                project='CMIP6',
+                dataset='model',
+                mip='Amon',
+            )
 
 
-class TestFixData(TestCase):
+class TestFixData():
     """Fix data tests."""
 
+    @pytest.fixture(autouse=True)
     def setUp(self):
         """Prepare for testing."""
         self.cube = Mock()
@@ -270,9 +252,10 @@ class TestFixData(TestCase):
                 'dataset': 'model',
                 'mip': 'mip',
                 'short_name': 'short_name',
-                'frequency': None,
+                'frequency': 'frequency',
             },
             'session': sentinel.session,
+            'frequency': 'frequency',
         }
 
     def test_fix(self):
@@ -288,9 +271,12 @@ class TestFixData(TestCase):
                     project='project',
                     dataset='model',
                     mip='mip',
+                    frequency='frequency',
                     session=sentinel.session,
                 )
-                self.checker.assert_called_once_with(self.intermediate_cube)
+                self.checker.assert_called_once_with(
+                    self.intermediate_cube
+                )
                 self.check_data.assert_called_once_with()
                 assert cube_returned is not self.cube
                 assert cube_returned is not self.intermediate_cube
@@ -312,6 +298,7 @@ class TestFixData(TestCase):
                     project='project',
                     dataset='model',
                     mip='mip',
+                    frequency='frequency',
                     session=sentinel.session,
                 )
                 self.checker.assert_called_once_with(self.cube)
@@ -322,25 +309,3 @@ class TestFixData(TestCase):
                 mock_get_fixes.assert_called_once_with(
                     **self.expected_get_fixes_call
                 )
-
-    def test_cmor_checker_called(self):
-        """Check that the cmor check is done."""
-        checker = Mock()
-        checker.return_value = Mock()
-        with patch('esmvalcore.cmor._fixes.fix.Fix.get_fixes',
-                   return_value=[]):
-            with patch('esmvalcore.cmor.fix._get_cmor_checker',
-                       return_value=checker) as get_mock:
-                fix_data(self.cube, 'short_name', 'CMIP6', 'model', 'mip',
-                         'frequency')
-                get_mock.assert_called_once_with(
-                    table='CMIP6',
-                    automatic_fixes=True,
-                    check_level=CheckLevels.DEFAULT,
-                    fail_on_error=False,
-                    frequency='frequency',
-                    mip='mip',
-                    short_name='short_name',
-                )
-                checker.assert_called_once_with(self.cube)
-                checker.return_value.check_data.assert_called_once_with()
diff --git a/tests/unit/cmor/test_generic_fix.py b/tests/unit/cmor/test_generic_fix.py
new file mode 100644
index 000000000..54703b93f
--- /dev/null
+++ b/tests/unit/cmor/test_generic_fix.py
@@ -0,0 +1,237 @@
+"""Unit tests for generic fixes."""
+
+from unittest.mock import sentinel
+
+import numpy as np
+import pytest
+from iris.coords import AuxCoord
+from iris.cube import Cube, CubeList
+
+from esmvalcore.cmor._fixes.fix import GenericFix, get_time_bounds
+from esmvalcore.cmor.table import get_var_info
+
+
+@pytest.fixture
+def time_coord():
+    """Time coordinate."""
+    time_coord = AuxCoord(
+        [15, 350],
+        standard_name='time',
+        units='days since 1850-01-01'
+    )
+    return time_coord
+
+
+@pytest.fixture
+def generic_fix():
+    """Generic fix object."""
+    vardef = get_var_info('CMIP6', 'CFmon', 'ta')
+    extra_facets = {'short_name': 'ta', 'project': 'CMIP6', 'dataset': 'MODEL'}
+    return GenericFix(vardef, extra_facets=extra_facets)
+
+
+@pytest.mark.parametrize(
+    'freq,expected_bounds',
+    [
+        ('mon', [[0, 31], [334, 365]]),
+        ('mo', [[0, 31], [334, 365]]),
+        ('yr', [[0, 365], [0, 365]]),
+        ('dec', [[0, 3652], [0, 3652]]),
+        ('day', [[14.5, 15.5], [349.5, 350.5]]),
+        ('6hr', [[14.875, 15.125], [349.875, 350.125]]),
+        ('3hr', [[14.9375, 15.0625], [349.9375, 350.0625]]),
+        ('1hr', [[14.97916666, 15.020833333], [349.97916666, 350.020833333]]),
+    ]
+)
+def test_get_time_bounds(time_coord, freq, expected_bounds):
+    """Test ``get_time_bounds`."""
+    bounds = get_time_bounds(time_coord, freq)
+    np.testing.assert_allclose(bounds, expected_bounds)
+
+
+def test_get_time_bounds_invalid_freq_fail(time_coord):
+    """Test ``get_time_bounds`."""
+    with pytest.raises(NotImplementedError):
+        get_time_bounds(time_coord, 'invalid_freq')
+
+
+def test_generic_fix_empty_long_name(generic_fix, monkeypatch):
+    """Test ``GenericFix``."""
+    # Artificially set long_name to empty string for test
+    monkeypatch.setattr(generic_fix.vardef, 'long_name', '')
+
+    cube = generic_fix._fix_long_name(sentinel.cube)
+
+    assert cube == sentinel.cube
+
+
+def test_generic_fix_empty_units(generic_fix, monkeypatch):
+    """Test ``GenericFix``."""
+    # Artificially set latitude units to empty string for test
+    coord_info = generic_fix.vardef.coordinates['latitude']
+    monkeypatch.setattr(coord_info, 'units', '')
+
+    ret = generic_fix._fix_coord_units(
+        sentinel.cube, coord_info, sentinel.cube_coord
+    )
+
+    assert ret is None
+
+
+def test_generic_fix_no_generic_lev_coords(generic_fix, monkeypatch):
+    """Test ``GenericFix``."""
+    # Artificially remove generic_lev_coords
+    monkeypatch.setattr(
+        generic_fix.vardef.coordinates['alevel'], 'generic_lev_coords', {}
+    )
+
+    cube = generic_fix._fix_alternative_generic_level_coords(sentinel.cube)
+
+    assert cube == sentinel.cube
+
+
+def test_requested_levels_2d_coord(generic_fix, mocker):
+    """Test ``GenericFix``."""
+    cube_coord = AuxCoord([[0]], standard_name='latitude', units='rad')
+    cmor_coord = mocker.Mock(requested=True)
+
+    ret = generic_fix._fix_requested_coord_values(
+        sentinel.cube, cmor_coord, cube_coord
+    )
+
+    assert ret is None
+
+
+def test_requested_levels_invalid_arr(generic_fix, mocker):
+    """Test ``GenericFix``."""
+    cube_coord = AuxCoord([0], standard_name='latitude', units='rad')
+    cmor_coord = mocker.Mock(requested=['a', 'b'])
+
+    ret = generic_fix._fix_requested_coord_values(
+        sentinel.cube, cmor_coord, cube_coord
+    )
+
+    assert ret is None
+
+
+def test_lon_no_fix_needed(generic_fix):
+    """Test ``GenericFix``."""
+    cube_coord = AuxCoord(
+        [0.0, 180.0, 360.0], standard_name='longitude', units='rad'
+    )
+
+    ret = generic_fix._fix_longitude_0_360(
+        sentinel.cube, sentinel.cmor_coord, cube_coord
+    )
+
+    assert ret == (sentinel.cube, cube_coord)
+
+
+def test_lon_too_low_to_fix(generic_fix):
+    """Test ``GenericFix``."""
+    cube_coord = AuxCoord(
+        [-370.0, 0.0], standard_name='longitude', units='rad'
+    )
+
+    ret = generic_fix._fix_longitude_0_360(
+        sentinel.cube, sentinel.cmor_coord, cube_coord
+    )
+
+    assert ret == (sentinel.cube, cube_coord)
+
+
+def test_lon_too_high_to_fix(generic_fix):
+    """Test ``GenericFix``."""
+    cube_coord = AuxCoord([750.0, 0.0], standard_name='longitude', units='rad')
+
+    ret = generic_fix._fix_longitude_0_360(
+        sentinel.cube, sentinel.cmor_coord, cube_coord
+    )
+
+    assert ret == (sentinel.cube, cube_coord)
+
+
+def test_fix_direction_2d_coord(generic_fix):
+    """Test ``GenericFix``."""
+    cube_coord = AuxCoord([[0]], standard_name='latitude', units='rad')
+
+    ret = generic_fix._fix_coord_direction(
+        sentinel.cube, sentinel.cmor_coord, cube_coord
+    )
+
+    assert ret == (sentinel.cube, cube_coord)
+
+
+def test_fix_direction_string_coord(generic_fix):
+    """Test ``GenericFix``."""
+    cube_coord = AuxCoord(['a'], standard_name='latitude', units='rad')
+
+    ret = generic_fix._fix_coord_direction(
+        sentinel.cube, sentinel.cmor_coord, cube_coord
+    )
+
+    assert ret == (sentinel.cube, cube_coord)
+
+
+def test_fix_direction_no_stored_direction(generic_fix, mocker):
+    """Test ``GenericFix``."""
+    cube = Cube(0)
+    cube_coord = AuxCoord([0, 1], standard_name='latitude', units='rad')
+    cmor_coord = mocker.Mock(stored_direction='')
+
+    ret = generic_fix._fix_coord_direction(cube, cmor_coord, cube_coord)
+
+    assert ret == (cube, cube_coord)
+
+
+def test_fix_metadata_not_fail_with_empty_cube(generic_fix):
+    """Generic fixes should not fail with empty cubes."""
+    fixed_cubes = generic_fix.fix_metadata([Cube(0)])
+
+    assert isinstance(fixed_cubes, CubeList)
+    assert len(fixed_cubes) == 1
+    assert fixed_cubes[0] == Cube(
+        0, standard_name='air_temperature', long_name='Air Temperature'
+    )
+
+
+@pytest.mark.parametrize(
+    'extra_facets', [{}, {'project': 'P', 'dataset': 'D'}]
+)
+def test_fix_metadata_multiple_cubes_fail(extra_facets):
+    """Generic fixes should fail when multiple invalid cubes are given."""
+    vardef = get_var_info('CMIP6', 'Amon', 'ta')
+    fix = GenericFix(vardef, extra_facets=extra_facets)
+    with pytest.raises(ValueError):
+        fix.fix_metadata([Cube(0), Cube(0)])
+
+
+def test_fix_metadata_no_extra_facets():
+    """Generic fixes should not fail when no extra facets are given."""
+    vardef = get_var_info('CMIP6', 'Amon', 'ta')
+    fix = GenericFix(vardef)
+    fixed_cubes = fix.fix_metadata([Cube(0)])
+
+    assert isinstance(fixed_cubes, CubeList)
+    assert len(fixed_cubes) == 1
+    assert fixed_cubes[0] == Cube(
+        0, standard_name='air_temperature', long_name='Air Temperature'
+    )
+
+
+def test_fix_data_not_fail_with_empty_cube(generic_fix):
+    """Generic fixes should not fail with empty cubes."""
+    fixed_cube = generic_fix.fix_data(Cube(0))
+
+    assert isinstance(fixed_cube, Cube)
+    assert fixed_cube == Cube(0)
+
+
+def test_fix_data_no_extra_facets():
+    """Generic fixes should not fail when no extra facets are given."""
+    vardef = get_var_info('CMIP6', 'Amon', 'ta')
+    fix = GenericFix(vardef)
+    fixed_cube = fix.fix_data(Cube(0))
+
+    assert isinstance(fixed_cube, Cube)
+    assert fixed_cube == Cube(0)
diff --git a/tests/unit/cmor/test_utils.py b/tests/unit/cmor/test_utils.py
new file mode 100644
index 000000000..f373524a7
--- /dev/null
+++ b/tests/unit/cmor/test_utils.py
@@ -0,0 +1,60 @@
+"""Unit tests for :mod:`esmvalcore.cmor._utils`."""
+
+import pytest
+from iris.cube import Cube
+
+from esmvalcore.cmor._utils import _get_single_cube
+
+
+@pytest.mark.parametrize(
+    'cubes', [[Cube(0)], [Cube(0, var_name='x')], [Cube(0, var_name='y')]]
+)
+def test_get_single_cube_one_cube(cubes, caplog):
+    """Test ``_get_single_cube``."""
+    single_cube = _get_single_cube(cubes, 'x')
+    assert single_cube == cubes[0]
+    assert not caplog.records
+
+
+@pytest.mark.parametrize(
+    'dataset_str,msg', [
+        (None, "Found variable x, but"),
+        ('XYZ', "Found variable x in XYZ, but"),
+    ]
+)
+@pytest.mark.parametrize(
+    'cubes', [
+        [Cube(0), Cube(0, var_name='x')],
+        [Cube(0, var_name='x'), Cube(0)],
+        [Cube(0, var_name='x'), Cube(0, var_name='x')],
+        [Cube(0), Cube(0), Cube(0, var_name='x')],
+    ]
+)
+def test_get_single_cube_multiple_cubes(cubes, dataset_str, msg, caplog):
+    """Test ``_get_single_cube``."""
+    single_cube = _get_single_cube(cubes, 'x', dataset_str=dataset_str)
+    assert single_cube == Cube(0, var_name='x')
+    assert len(caplog.records) == 1
+    log = caplog.records[0]
+    assert log.levelname == 'WARNING'
+    assert msg in log.message
+
+
+@pytest.mark.parametrize(
+    'dataset_str,msg', [
+        (None, "More than one cube found for variable x but"),
+        ('XYZ', "More than one cube found for variable x in XYZ but"),
+    ]
+)
+@pytest.mark.parametrize(
+    'cubes', [
+        [Cube(0), Cube(0)],
+        [Cube(0, var_name='y'), Cube(0)],
+        [Cube(0, var_name='y'), Cube(0, var_name='z')],
+        [Cube(0), Cube(0), Cube(0, var_name='z')],
+    ]
+)
+def test_get_single_cube_no_cubes_fail(cubes, dataset_str, msg):
+    """Test ``_get_single_cube``."""
+    with pytest.raises(ValueError, match=msg):
+        _get_single_cube(cubes, 'x', dataset_str=dataset_str)
diff --git a/tests/unit/recipe/test_recipe.py b/tests/unit/recipe/test_recipe.py
index a437221a0..498dd606d 100644
--- a/tests/unit/recipe/test_recipe.py
+++ b/tests/unit/recipe/test_recipe.py
@@ -541,7 +541,6 @@ def test_get_default_settings(mocker):
 
     settings = _recipe._get_default_settings(dataset)
     assert settings == {
-        'load': {'callback': 'default'},
         'remove_supplementary_variables': {},
         'save': {'compress': False, 'alias': 'sic'},
     }
diff --git a/tests/unit/test_cmor_api.py b/tests/unit/test_cmor_api.py
index 781ce3015..ac61c5006 100644
--- a/tests/unit/test_cmor_api.py
+++ b/tests/unit/test_cmor_api.py
@@ -1,4 +1,6 @@
 # flake8: noqa
+from unittest.mock import sentinel
+
 import esmvalcore.cmor.check
 import esmvalcore.cmor.fix
 import esmvalcore.cmor.fixes
@@ -11,3 +13,114 @@ from esmvalcore.cmor.check import (
     cmor_check_data,
     cmor_check_metadata,
 )
+
+
+def test_cmor_check_metadata(mocker):
+    """Test ``cmor_check_metadata``"""
+    mock_get_cmor_checker = mocker.patch.object(
+        esmvalcore.cmor.check, '_get_cmor_checker', autospec=True
+    )
+    (
+        mock_get_cmor_checker.return_value.return_value.check_metadata.
+        return_value
+    ) = sentinel.checked_cube
+
+    cube = cmor_check_metadata(
+        sentinel.cube,
+        sentinel.cmor_table,
+        sentinel.mip,
+        sentinel.short_name,
+        sentinel.frequency,
+        check_level=sentinel.check_level,
+    )
+
+    mock_get_cmor_checker.assert_called_once_with(
+        sentinel.cmor_table,
+        sentinel.mip,
+        sentinel.short_name,
+        sentinel.frequency,
+        check_level=sentinel.check_level,
+    )
+    mock_get_cmor_checker.return_value.assert_called_once_with(sentinel.cube)
+    (
+        mock_get_cmor_checker.return_value.return_value.check_metadata.
+        assert_called_once_with()
+    )
+    assert cube == sentinel.checked_cube
+
+
+def test_cmor_check_data(mocker):
+    """Test ``cmor_check_data``"""
+    mock_get_cmor_checker = mocker.patch.object(
+        esmvalcore.cmor.check, '_get_cmor_checker', autospec=True
+    )
+    (
+        mock_get_cmor_checker.return_value.return_value.check_data.
+        return_value
+    ) = sentinel.checked_cube
+
+    cube = cmor_check_data(
+        sentinel.cube,
+        sentinel.cmor_table,
+        sentinel.mip,
+        sentinel.short_name,
+        sentinel.frequency,
+        check_level=sentinel.check_level,
+    )
+
+    mock_get_cmor_checker.assert_called_once_with(
+        sentinel.cmor_table,
+        sentinel.mip,
+        sentinel.short_name,
+        sentinel.frequency,
+        check_level=sentinel.check_level,
+    )
+    mock_get_cmor_checker.return_value.assert_called_once_with(sentinel.cube)
+    (
+        mock_get_cmor_checker.return_value.return_value.check_data.
+        assert_called_once_with()
+    )
+    assert cube == sentinel.checked_cube
+
+
+def test_cmor_check(mocker):
+    """Test ``cmor_check``"""
+    mock_cmor_check_metadata = mocker.patch.object(
+        esmvalcore.cmor.check,
+        'cmor_check_metadata',
+        autospec=True,
+        return_value=sentinel.cube_after_check_metadata,
+    )
+    mock_cmor_check_data = mocker.patch.object(
+        esmvalcore.cmor.check,
+        'cmor_check_data',
+        autospec=True,
+        return_value=sentinel.cube_after_check_data,
+    )
+
+    cube = cmor_check(
+        sentinel.cube,
+        sentinel.cmor_table,
+        sentinel.mip,
+        sentinel.short_name,
+        sentinel.frequency,
+        sentinel.check_level,
+    )
+
+    mock_cmor_check_metadata.assert_called_once_with(
+        sentinel.cube,
+        sentinel.cmor_table,
+        sentinel.mip,
+        sentinel.short_name,
+        sentinel.frequency,
+        check_level=sentinel.check_level,
+    )
+    mock_cmor_check_data.assert_called_once_with(
+        sentinel.cube_after_check_metadata,
+        sentinel.cmor_table,
+        sentinel.mip,
+        sentinel.short_name,
+        sentinel.frequency,
+        check_level=sentinel.check_level,
+    )
+    assert cube == sentinel.cube_after_check_data
diff --git a/tests/unit/test_dataset.py b/tests/unit/test_dataset.py
index 56baaa60d..1a0114e8c 100644
--- a/tests/unit/test_dataset.py
+++ b/tests/unit/test_dataset.py
@@ -1684,7 +1684,6 @@ def test_load(mocker, session):
 
     load_args = {
         'load': {
-            'callback': 'default',
             'ignore_warnings': None,
         },
         'fix_file': {