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

  1. List loaded users first: um = op.init(client, path, None)[0]; print(list(um.users)) and use an exact id from it.
  2. Ensure the user was added via add_user / registered in users_file before reporting on it.
  3. 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

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


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