Skip to content

brev create cannot set region: location/subLocation exist in the request struct but are only populated via launchables #454

Description

@theFong

Summary

brev create cannot place an instance in a specific region. The control-plane API does accept location / subLocation on the plain (non-launchable) create endpoint, and store.CreateWorkspacesOptions already declares both fields — but nothing outside the launchable path ever populates them. The result is that every plain brev create silently inherits whatever default location the instance-type catalog happens to carry for that type.

For n2d-standard-2 that default is currently asia-south1, so a user in the US who runs brev create mybox --type n2d-standard-2 deterministically gets an instance in Mumbai with no flag available to change it and nothing in the output indicating a region was chosen.

Impact

I hit this provisioning a small CPU node intended to sit next to existing us-west2 infrastructure. Three delete/recreate cycles all landed in asia-south1 — it reads like capacity flakiness, but it's deterministic. Cross-region latency to the rest of the fleet was ~238 ms.

Notably, an existing instance of the same type (n2d-standard-2) in the same org is in us-west2, so the placement is achievable — the CLI just can't ask for it.

Root cause

The fields exist in the request struct, with omitempty:

// pkg/store/workspace.go:101-102
InstanceType string `json:"instanceType"`
Location     string `json:"location,omitempty"`
SubLocation  string `json:"subLocation,omitempty"`
DiskStorage  string `json:"diskStorage"`

The only assignments to them in the repo are in the launchable path:

// pkg/cmd/gpucreate/gpucreate.go:1365-1376
func applyLaunchableWorkspaceRequest(cwOptions *store.CreateWorkspacesOptions, wsReq store.LaunchableWorkspaceRequest) {
	if wsReq.Location != "" {
		cwOptions.Location = wsReq.Location
	}
	if wsReq.SubLocation != "" {
		cwOptions.SubLocation = wsReq.SubLocation
	}

createWorkspace() (the non-launchable path) never sets either, so omitempty drops them and the server falls back to the catalog default.

Two related places where location data is available but discarded:

  1. gpusearch.InstanceType parses location, sub_location, and available_locations, but ProcessInstances() maps into GPUInstanceInfo, which has no location field — so the data is dropped, and brev search has no LOCATION column to reveal where a type would land.
  2. GetAllInstanceTypesWithCloudCreds passes uniqueInstanceType = true, deduplicating region variants down to a single row; GetCloudCredID() then takes the first match.

Reproduction

brev create mybox --type n2d-standard-2
# -> lands in asia-south1 regardless of caller location; no flag to influence it

Confirm the catalog default that drives it:

curl -s -H "Authorization: Bearer $TOKEN" \
  "https://brevapi.us-west-2-prod.control-plane.brev.dev/api/instances/alltypesavailable/$ORG_ID" \
| jq '.[] | .[]? | select(.type=="n2d-standard-2")
      | {location, sub_location, available_locations}'

Returns location: "asia-south1", with available_locations containing 40 regions including us-west2.

The server already supports this (verified)

Adding the field to the same plain-create endpoint works. I ran this and it returned region: us-west2:

curl -X POST "https://brevapi.us-west-2-prod.control-plane.brev.dev/api/organizations/$ORG_ID/workspaces" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "name": "mybox",
    "workspaceGroupId": "GCP",
    "workspaceClassId": "2x8",
    "workspaceTemplateId": "<template-id>",
    "instanceType": "n2d-standard-2",
    "diskStorage": "120Gi",
    "workspaceVersion": "v1",
    "vmBuild": {"forceJupyterInstall": true},
    "location": "us-west2",
    "subLocation": "us-west2-a"
  }'

So this is purely a CLI gap, not a backend limitation. It's also consistent with the existing test comment in gpucreate_test.go, which notes that the original bug was fields the server expected (firewallRules, subLocation) being missing from the request body.

Requested change

  1. Add --location (and optionally --sub-location) flags to brev create, wired into CreateWorkspacesOptions.Location / .SubLocation.
  2. Validate the value against the type's available_locations and fail with the list on mismatch.
  3. Surface location in brev search output (a LOCATION column) and in brev create --dry-run, so the default is visible before creating.
  4. Consider whether uniqueInstanceType = true should dedupe across regions, given it can hide region variants entirely.

Even just (3) alone would have saved a lot of time here — the current behavior is invisible until after the instance exists.

Environment

  • brev v0.6.329 (also checked v0.6.334 release notes; no region-related changes)
  • Linux, GCP provider, instance type n2d-standard-2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions