microsoft/qlib · error · ValueError
This RecordTemp did not set recorder yet.
Error message
This RecordTemp did not set recorder yet.
What it means
RecordTemp.recorder is a property that raises ValueError when self._recorder is None. RecordTemp (and subclasses like SignalRecord, PortAnaRecord) must be bound to a QlibRecorder to know where to save artifacts; a None recorder means generate/save/load cannot proceed, so the property fails fast.
Source
Thrown at qlib/workflow/record_temp.py:65
return "/".join(names)
def save(self, **kwargs):
"""
It behaves the same as self.recorder.save_objects.
But it is an easier interface because users don't have to care about `get_path` and `artifact_path`
"""
art_path = self.get_path()
if art_path == "":
art_path = None
self.recorder.save_objects(artifact_path=art_path, **kwargs)
def __init__(self, recorder):
self._recorder = recorder
@property
def recorder(self):
if self._recorder is None:
raise ValueError("This RecordTemp did not set recorder yet.")
return self._recorder
def generate(self, **kwargs):
"""
Generate certain records such as IC, backtest etc., and save them.
Parameters
----------
kwargs
Return
------
"""
raise NotImplementedError(f"Please implement the `generate` method.")
def load(self, name: str, parents: bool = True):
"""
It behaves the same as self.recorder.load_object.View on GitHub (pinned to 79633dd950)
Solutions
- Create/start a recorder first (R.start(...) or R.get_recorder(...)) and pass the live recorder into the record temp constructor
- Guard the lookup: only build the RecordTemp when the recorder is not None
- Check the 'record' section of your workflow config — record classes listed there are instantiated with the active recorder; make sure a run is active
Example fix
# before
with R.start('my_exp'):
pass
rec = R.get_recorder() # may be None if no run matched
sr = SignalRecord(recorder=rec) # rec is None -> later ValueError
# after
with R.start('my_exp'):
rec = R.get_recorder()
assert rec is not None, 'no active recorder'
sr = SignalRecord(recorder=rec)
sr.generate() Defensive patterns
Strategy: validation
Validate before calling
from qlib.workflow import R
def get_record(recorder, record_cls):
if recorder is None:
raise ValueError('no active recorder; call R.start(...) first')
return record_cls(recorder=recorder) Type guard
def is_live_recorder(rec) -> bool:
return rec is not None and hasattr(rec, 'save_objects') and getattr(rec, 'id', None) is not None Try / catch
try:
rt.recorder # property access
except ValueError as e:
raise RuntimeError('record temp has no recorder; recreate it inside R.start context') from e Prevention
- Create record temps only inside `with R.start(...)` blocks
- Check R.get_recorder() results for None before passing them on
- When listing record classes in workflow configs, keep them as strings resolved after the run starts
When it happens
Trigger: Constructing RecordTemp(recorder=None) or a subclass whose __init__ propagates recorder=None; using a record template before R.start() created a recorder; passing the result of a failed R.get_recorder() call; deserializing/pickling a record temp without its recorder.
Common situations: Creating record objects manually outside a with R.start(...) context; recorder lookup returning None and being passed through unchecked; forgetting to attach a recorder when composing custom record lists for the 'record' field in a workflow config.
Related errors
- {freq} is not supported in NumpyQuote
- {method} is not supported
- Invalid Qlib configuration (note: the global config has alre
- provider_uri cannot be None
- risk_analysis accumulation mode {mode} is not supported. Exp
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/5869bf4f21e6f8f0.
Report an issue: GitHub.