Repository navigation
[UX] Show No quota and No balance when provisioning fails - #4372
Draft
peterschmidt85 wants to merge 1 commit into
Draft
peterschmidt85 wants to merge 1 commit into
peterschmidt85 wants to merge 1 commit into
Conversation
peterschmidt85
marked this pull request as ready for review
October 16, 2026 08:09
Collaborator
Is this addressed? |
peterschmidt85
marked this pull request as draft
October 16, 2026 10:36
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Offers correctly show No quota / No balance, but fleet/job provisioning reports No offers / No capacity. In dstack Factory (including Sky), quota or billing restrictions therefore look like provider capacity problems.
Steps to reproduce
On an affected Factory/Sky server, use a project with a
dstackbackend, positive owner balance, no reusable instances, and available Nebius offers matchingcpu: 8..andgpu: H100.Set the project's CPU quota to
4. Matching offers should now showno_quota. Savefleet.ymland rundstack apply -f fleet.yml:Save
task.ymland rundstack apply -f task.yml, confirming submission:Inspect the failed job. To reproduce fleet-instance provisioning, apply a second fleet with the same resources, a different name, and
nodes: 1; inspect its terminated instance.Repeat with sufficient quota and zero owner balance to exercise
no_balance. Use another supported GPU if H100 offers are unavailable.Actual behaviour
Expected behaviour
Report No quota / No balance when no usable offers remain and all matching rejected offers share that reason. Try available alternatives; keep the generic failure for mixed reasons. Preserve the existing lifecycle statuses and retry policy.
For example:
Notes
Root cause:
create_cloud_instance()and_provision_new_capacity()request offers withexclude_not_available=True.get_backend_offers()dropsNO_QUOTA/NO_BALANCEoffers before those callers choose a termination reason, leaving their generic no-offers/no-capacity paths.Fix:
on_unavailable_offercallback toget_backend_offers(). Before discarding an offer,get_offers_by_requirements()records its availability inUnavailableOffers. Reuse_OfferFilterand block-divisibility checks so only matching offers contribute; keep only distinct reasons, without copying or retaining offers.{NO_QUOTA}or{NO_BALANCE}. Fleet instances use the newInstanceTerminationReason.NO_QUOTAor existingNO_BALANCE. Jobs return newFAILED_TO_START_DUE_TO_NO_QUOTA/FAILED_TO_START_DUE_TO_NO_BALANCEthrough_FailedNewCapacityProvisioning.reasoninstead of hardcoding no capacity.JobStatus.FAILED,RetryEvent.NO_CAPACITY, and theno quota/no balancestatus messages. Include them in the run'sretryingdisplay and the existing superseded-submission cleanupDELETEpredicate.MASTER_FAILED. Omit the CLI runner-log hint for these failures because no runner started.Performance: this implementation took about 17% longer to process the same jobs in a local stress test: 2.14 s before vs. 2.51 s after (160 jobs, 10,000 blocked offers per job, 80 concurrent workers; provider responses simulated). The extra CPU work can delay other server work under load. There are no additional DB queries or cloud API calls, and offer classification holds no DB connection, but this does not mean zero server latency impact.
Deployment: during a rolling update, old and new servers share the DB. If a new server saves one of the new job failure reasons, an old server fails when reading that job because it does not recognize the value. Safe rolling updates need two releases: first teach every server to read and handle these reasons without saving them; then start saving them. This draft must be split into those two releases before deployment.