Commit c6f2e21
fix(env): scope branch-override lookup by branchId (#109)
## Problem
`project env update --branch` and `project env add --branch` fail
contradictorily on any branch that already has an override for a key:
- `add --branch` → server **409** "already exists in this scope"
- `update --branch` → CLI **`ENV_VARIABLE_NOT_FOUND`** "not found in
branch:…"
One says the variable exists, the other says it doesn't. Neither path
can touch an existing branch override, so re-running a workflow that
sets a per-branch override hard-fails.
## Root cause
`findVariableByNaturalKey` listed environment variables by `(projectId,
class, key)` and filtered by branch **client-side**, inspecting only the
first page. `GET /v1/environment-variables` is paginated (default
`limit=100`, ordered `createdAt asc`). Once a project accumulates more
than a page of preview overrides for a given key, the *newest* branch's
row sorts onto a later page and the lookup returns `null` even though
the row exists on the server.
Downstream:
- `update`'s pre-lookup returns null → throws `ENV_VARIABLE_NOT_FOUND`
before it ever PATCHes.
- `add`'s existence pre-check also returns null → it POSTs → the server
(which enforces uniqueness on `projectId, branchId, class, key`) rejects
with 409.
The endpoint already supports a `branchId` filter — the lookup just
wasn't using it.
## Why this surfaced now
This is a latent bug (the branch-override lookup has never passed
`branchId`), triggered by data volume rather than a code change. In one
affected project, the count of preview-class rows for
`BUILD_RUNNER_BASE_URL` had just crossed the page limit (104 rows, 104
distinct branches, 4 past the first page) — so the freshly-created
branch override was the row that fell off page 1. First deploy of a
branch (which takes the `add`/create path) still worked; every re-deploy
(the lookup path) failed. That first-run-vs-rerun signature is exactly
what the pagination boundary produces.
## Fix
Pass `branchId` to the list query for branch-scoped lookups so the
server returns the single exact row regardless of how many branches
exist. Role-scoped lookups (`branchId === null`) are unchanged.
## Testing
- `pnpm --filter @prisma/cli exec tsc --noEmit` — clean
- `pnpm --filter @prisma/cli test` — 563 passed
- Added a regression test asserting the branch-override lookup sends
`branchId`; verified it fails without the source change and passes with
it.
## Known residual (out of scope)
Role-scoped (template) lookups still fetch a single page and filter
`branchId === null` client-side — the same pagination class of bug in
theory — but the list query type only accepts `branchId?: string`, so
there's no way to express "branchId IS NULL" as a server filter today,
and template rows are singular per key and created early (page 1). Worth
a follow-up if the API grows a null-branch filter. Separately, the
projects hitting this also have a data-hygiene problem: preview-branch
overrides (and their branches/databases) are never cleaned up, which is
what let the row count climb past the page limit in the first place.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>1 parent f152fe3 commit c6f2e21
2 files changed
Lines changed: 65 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
36 | 37 | | |
37 | 38 | | |
38 | 39 | | |
| |||
41 | 42 | | |
42 | 43 | | |
43 | 44 | | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
44 | 48 | | |
45 | 49 | | |
46 | 50 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
944 | 944 | | |
945 | 945 | | |
946 | 946 | | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
947 | 1008 | | |
948 | 1009 | | |
949 | 1010 | | |
| |||
0 commit comments