You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Python API Run.logs() returns nothing for a finished run #4175
fromdstack.apiimportClientc=Client.from_config()
r=c.runs.get("<a run that has finished>")
print(len(b"".join(r.logs()))) # 0print(len(b"".join(r.logs(replica_num=0)))) # the actual logs
Actual behaviour
logs() yields nothing for any terminal run - no exception, no warning. dstack logs <same run> prints the logs in full.
_find_job matches on replica_num alone when it is given, but when it is None it matches only a submission whose status is RUNNING:
Once a run is terminal nothing is RUNNING, so _find_job returns None and logs() returns an empty generator. The CLI is unaffected because its --replica argparse default is 0, so it never passes None.
Expected behaviour
logs() with default arguments should return the logs of a finished run, as the CLI does - fall back to replica 0 when no submission is running, or raise instead of yielding nothing.
Some history, so the fix doesn't undo the rolling-deploy behaviour.
Both logs() and attach() defaulted to replica_num=0 with no status check until #2821 (rolling deployment for services) changed them to None and added the RUNNING condition, documented as "any running replica". That's right for attach: under a rolling deploy replica 0 may be draining or gone, and you can't tunnel into a dead container anyway.
It's wrong only for logs(), which shares _find_job but should outlive the replica. So the fallback belongs in the logs path; attach should keep matching any running replica.
Activity
r4victor commentedon Aug 20, 2026
Some history, so the fix doesn't undo the rolling-deploy behaviour.
Both
logs()andattach()defaulted toreplica_num=0with no status check until #2821 (rolling deployment for services) changed them toNoneand added theRUNNINGcondition, documented as "any running replica". That's right forattach: under a rolling deploy replica 0 may be draining or gone, and you can't tunnel into a dead container anyway.It's wrong only for
logs(), which shares_find_jobbut should outlive the replica. So the fallback belongs in the logs path;attachshould keep matching any running replica.