microsoft/qlib · error · ValueError

generate_portfolio_metrics should be True if you want to gen

Error message

generate_portfolio_metrics should be True if you want to generate portfolio_metrics

What it means

DiskDatasetCache._dataset_uri (qlib/data/cache.py:762) raises the same inst_processor guard as _dataset: with disk_cache != 0 and non-empty inst_processors, qlib cannot serve a shared dataset-cache URI whose contents would depend on the per-instrument processors. The fix set is identical — disk_cache=0 (client-side load path, which only walks expression caches) or no dataset cache.

Source

Thrown at qlib/backtest/account.py:413

            trade_start_time=trade_start_time,
            trade_exchange=trade_exchange,
            atomic=atomic,
            outer_trade_decision=outer_trade_decision,
            trade_info=trade_info,
            inner_order_indicators=inner_order_indicators,
            decision_list=decision_list,
            indicator_config=indicator_config,
        )

    def get_portfolio_metrics(self) -> Tuple[pd.DataFrame, dict]:
        """get the history portfolio_metrics and positions instance"""
        if self.is_port_metr_enabled():
            assert self.portfolio_metrics is not None
            _portfolio_metrics = self.portfolio_metrics.generate_portfolio_metrics_dataframe()
            _positions = self.get_hist_positions()
            return _portfolio_metrics, _positions
        else:
            raise ValueError("generate_portfolio_metrics should be True if you want to generate portfolio_metrics")

    def get_trade_indicator(self) -> Indicator:
        """get the trade indicator instance, which has pa/pos/ffr info."""
        return self.indicator

View on GitHub (pinned to 79633dd950)

Solutions

  1. Pass disk_cache=0 in D.features so the server only checks expression caches and the client applies inst_processors itself
  2. Run qlib.init(dataset_cache=None) to remove the dataset cache from the provider chain
  3. Move instrument-level processing out of the data layer into dataset processors (DataHandlerLP)

Example fix

# before
uri = D.features(insts, fields, start, end, disk_cache=1, inst_processors=[p])  # ValueError

# after
uri = D.features(insts, fields, start, end, disk_cache=0, inst_processors=[p])
Defensive patterns

Strategy: validation

Validate before calling

assert not (inst_processors and disk_cache), \
    "inst_processors require disk_cache=0 with a configured dataset cache"

Type guard

def safe_disk_cache(disk_cache: int, inst_processors) -> int:
    return 0 if inst_processors else disk_cache

Try / catch

try:
    uri = cache.dataset(insts, fields, start, end, disk_cache=1, inst_processors=procs, return_uri=True)
except ValueError as e:
    if "does not support inst_processor" in str(e):
        uri = cache.dataset(insts, fields, start, end, disk_cache=0, inst_processors=procs, return_uri=True)
    else:
        raise

Prevention

When it happens

Trigger: Requesting a dataset cache URI (D.features with disk_cache=1 in client/server mode, or DatasetCache.dataset with return_uri semantics) while passing inst_processors; the disk_cache=0 branch above it returns "" after multi_cache_walker, but any other value plus processors triggers the ValueError.

Common situations: Client/server qlib deployments combining instrument processors with dataset-cache serving; switching a pipeline to inst_processors without changing the disk_cache flag.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/ab3696a0a64b954f. Report an issue: GitHub.