microsoft/qlib · error · ValueError
Cannot find user
Error message
Cannot find user
What it means
Raised by OnlineOperator.check_user (operator.py:299) when the requested id is not in the loaded UserManager's users dict. The report/risk-analysis step needs the user's portfolio_metrics, so the user must exist and be loaded first. Note the message has a formatting bug — the string has no {} placeholder, so .format(id) is a no-op and the id never appears in the error text.
Source
Thrown at qlib/contrib/online/operator.py:299
um.save_user_data(id)
self.show(id, path, bench)
def show(self, id, path, bench="SH000905"):
"""show the newly report (mean, std, information_ratio, annualized_return)
Parameters
----------
id : str
user id, need to be unique
path : str
Path to save user account.
bench : str
The benchmark that our result compared with.
'SH000905' for csi500, 'SH000300' for csi300
"""
um = self.init(self.client, path, None)[0]
if id not in um.users:
raise ValueError("Cannot find user ".format(id))
bench = D.features([bench], ["$change"]).loc[bench, "$change"]
portfolio_metrics = um.users[id].account.portfolio_metrics.generate_portfolio_metrics_dataframe()
portfolio_metrics["bench"] = bench
analysis_result = {}
r = (portfolio_metrics["return"] - portfolio_metrics["bench"]).dropna()
analysis_result["excess_return_without_cost"] = risk_analysis(r)
r = (portfolio_metrics["return"] - portfolio_metrics["bench"] - portfolio_metrics["cost"]).dropna()
analysis_result["excess_return_with_cost"] = risk_analysis(r)
print("Result:")
print("excess_return_without_cost:")
print(analysis_result["excess_return_without_cost"])
print("excess_return_with_cost:")
print(analysis_result["excess_return_with_cost"])
def run():
fire.Fire(Operator)
View on GitHub (pinned to 79633dd950)
Solutions
- List loaded users first: um = op.init(client, path, None)[0]; print(list(um.users)) and use an exact id from it.
- Ensure the user was added via add_user / registered in users_file before reporting on it.
- If the CSV is out of sync, re-register the user or fix users_file so load_users picks it up.
Example fix
# before op.check_user(id="u_9", path=p, bench="SH000300") # ValueError: Cannot find user # after um = op.init(op.client, p, None)[0] print(list(um.users)) # discover exact id, e.g. 'u09' op.check_user(id="u09", path=p, bench="SH000300")
Defensive patterns
Strategy: validation
Validate before calling
um = op.init(op.client, path, None)[0]
if id not in um.users:
raise KeyError(f"unknown user id {id!r}; loaded users: {sorted(um.users)}")
op.check_user(id=id, path=path, bench="SH000300") Type guard
def user_exists(um, user_id) -> bool:
return user_id in um.users Prevention
- Discover ids from list(um.users) instead of hard-coding guesses.
- Register users via add_user so users_file stays authoritative.
- Note the error message omits the id (formatting bug in qlib) — log your own id.
When it happens
Trigger: Calling op.check_user(id=..., ...) with a typo'd id, before um.load_users() has run (init does load via UserManager in operator.init), or for a user whose data folder exists but is not recorded in users_file.
Common situations: Reports requested for a user id with different casing/format; users_file CSV out of sync with the folders on disk; calling check_user right after manually copying a user folder without registering it.
Related errors
- Cannot find user data {}
- add date is not tradable date
- Can't find the BASE_CONFIG file: {base_config_path}
- User {} has been loaded
- Cannot find user {}
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/8f0346538c1aabde.
Report an issue: GitHub.