freqtrade/freqtrade · error · OperationalException

Legacy hyperopt results are no longer supported.Please rerun

Error message

Legacy hyperopt results are no longer supported.Please rerun hyperopt or use an older version to load this file.

What it means

Thrown by HyperoptTools._test_hyperopt_results_exist when the results file exists, is non-empty, and has a '.pickle' suffix. Older freqtrade releases stored hyperopt epochs as pickled lists (hyperopt_results.pickle); current versions use a different serialized format, and pickle files are both incompatible and a potential security hazard, so loading is refused outright. The message tells the user the file must be regenerated.

Source

Thrown at freqtrade/optimize/hyperopt_tools.py:137

        Stream hyperopt results from file
        """
        import rapidjson

        logger.info(f"Reading epochs from '{results_file}'")
        with results_file.open("r") as f:
            data = []
            for line in f:
                data += [rapidjson.loads(line)]
                if len(data) >= batch_size:
                    yield data
                    data = []
        yield data

    @staticmethod
    def _test_hyperopt_results_exist(results_file) -> bool:
        if results_file.is_file() and results_file.stat().st_size > 0:
            if results_file.suffix == ".pickle":
                raise OperationalException(
                    "Legacy hyperopt results are no longer supported."
                    "Please rerun hyperopt or use an older version to load this file."
                )
            return True
        else:
            # No file found.
            return False

    @staticmethod
    def load_filtered_results(results_file: Path, config: Config) -> tuple[list, int]:
        filteroptions = {
            "only_best": config.get("hyperopt_list_best", False),
            "only_profitable": config.get("hyperopt_list_profitable", False),
            "filter_min_trades": config.get("hyperopt_list_min_trades", 0),
            "filter_max_trades": config.get("hyperopt_list_max_trades", 0),
            "filter_min_avg_time": config.get("hyperopt_list_min_avg_time"),
            "filter_max_avg_time": config.get("hyperopt_list_max_avg_time"),
            "filter_min_avg_profit": config.get("hyperopt_list_min_avg_profit"),

View on GitHub (pinned to 1c8edfe4d1)

Solutions

  1. Delete or move the legacy file: `rm user_data/hyperopt_results/hyperopt_results.pickle`.
  2. Re-run the hyperopt with the current version to produce a fresh, compatible results file.
  3. If the old results are important, load them with the old freqtrade version first and export/record the parameters manually.

Example fix

# before: user_data/hyperopt_results/hyperopt_results.pickle exists from old version
freqtrade hyperopt-list
# after
mv user_data/hyperopt_results/hyperopt_results.pickle ~/backup/
freqtrade hyperopt-list
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def is_legacy_results_file(results_file: Path) -> bool:
    return results_file.suffix == ".pickle" and results_file.is_file() and results_file.stat().st_size > 0

Try / catch

from freqtrade.exceptions import OperationalException

try:
    HyperoptTools.load_filtered_results(results_file, config)
except OperationalException as e:
    if "Legacy hyperopt results" in str(e):
        archive/delete the .pickle file and rerun hyperopt
    else:
        raise

Prevention

When it happens

Trigger: Running `freqtrade hyperopt-list`, `hyperopt-show`, or resuming hyperopt in a user_data/hyperopt_results directory that still contains a legacy hyperopt_results.pickle from an old installation.

Common situations: Upgrading freqtrade in place without cleaning user_data/hyperopt_results; restoring a backup of results from an old bot.

Related errors


AI-assisted analysis of freqtrade/freqtrade@1c8edfe4d1 (2026-08-15). Data as JSON: /api/errors/703c1330f7ed93bd. Report an issue: GitHub.