Conversation
… terminate Terminating a workspace runs resetCurrentPaymodel in a goroutine, which sets current_pay_model=false on *every* row for that user. On commons where users are never asked to pick a pay model, that leaves them unable to launch again: getCurrentPayModel finds no row with current=true, sees that active rows do exist, and returns nil, so /launch responds 500 with "Current Paymodel is not set. Launch forbidden". The default-pay-model fallback immediately below is unreachable in this case -- it only fires for users with zero rows in the table. Add an opt-in "auto-select-single-paymodel" config key. When set, a user whose only active pay model is not flagged current has that row returned as their current one. The row is returned as-is rather than substituting DefaultPayModel so it keeps its bmh_workspace_id: pods are annotated with the right paymodel_type and updatePayModelCost can still find the row to bill, and the row's own hard/soft limits and accrued total-usage apply. Users with more than one pay model are untouched -- they have a real choice to make and the flag must not make it for them. Default is off, so behaviour is unchanged for every commons that does not opt in.
jbarno
approved these changes
Sep 24, 2026
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.
Users on
vpodc.data-commons.orgare currently unable to launch workspaces after terminating one. This adds an opt-in fix.The bug
Terminating a workspace fires this goroutine (
hatchery.go:629):resetCurrentPaymodelInDBsetscurrent_pay_model = falseon every row for that user. On the next launch,getCurrentPayModelhits this branch (paymodels.go:108):The row is still
request_status: "active", so it returnsnil, andhatchery.go:516responds 500Current Paymodel is not set. Launch forbidden. Thedefault-pay-modelfallback is unreachable — it only fires for users with zero rows.Observed in vadcprod over two days across three users:
GET /paymodelsfor an affected user:{ "current_pay_model": null, "all_pay_models": [ { "bmh_workspace_id": "3813c208-...", "request_status": "active", "current_pay_model": false, "hard-limit": 5, "soft-limit": 4 } ] }The intended recovery is re-selecting via
POST /setpaymodel, but on a commons usingdefault-pay-modelas a blanket trial that choice is never surfaced, so users are simply stuck.The fix
New opt-in key
"auto-select-single-paymodel". When set, a user whose only active pay model is not flagged current gets that row returned as current.Returning the user’s own row — rather than substituting
DefaultPayModel— is deliberate.DefaultPayModelhas nobmh_workspace_id, so pods would be annotated with an emptypaymodel_type;handlePodDeletedwould then passpodPaymodelID == ""and skipupdatePayModelCostentirely, silently breaking cost tracking. Keeping the real row preserves the workspace ID, itshard-limit/soft-limit, and accruedtotal-usage.Users with 2+ pay models are untouched: they have a real choice and the flag must not make it for them.
Tests
Three cases added to
Test_GetCurrentPayModel, all passing; the 5 existing cases still pass unchanged.AutoSelectSingle_SingleActiveNotCurrentAutoSelectSingle_MultipleActiveNotCurrentnil(unchanged)AutoSelectSingleDisabled_SingleActiveNotCurrentnil(unchanged)Verified the new tests fail without the
paymodels.gochange and pass with it.go build ./...,go vet, andgofmtare clean.Note:
TestCreateLogGroupfails on this branch, but it also fails on clean master — pre-existing and unrelated.Rollout
Default is off; no commons changes behavior until it opts in. For vpodc, add to the hatchery JSON in gen3-gitops:
Existing stuck rows self-heal on the next launch — no DynamoDB surgery needed.
Not addressed here
true. Opposite inconsistency, worth a separate look."priciing"typo zeroing all workspace costs — fixed in fix(vpodc): correct "priciing" typo so hatchery cost tracking works gen3-gitops#2124.