|
| 1 | +--- |
| 2 | +title: local auth env sync must use the real Convex CLI entrypoint |
| 3 | +date: 2026-04-17 |
| 4 | +category: integration-issues |
| 5 | +module: kitcn cli env sync |
| 6 | +problem_type: integration_issue |
| 7 | +component: development_workflow |
| 8 | +symptoms: |
| 9 | + - auth bootstrap can fail at `generated/auth:getLatestJwks` even after the backend is ready |
| 10 | + - `kitcn add auth`, `kitcn env push`, or `kitcn dev --bootstrap` can print JWKS output and still exit non-zero on some runtime/platform combinations |
| 11 | + - Windows Bun runs can trip `Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)` after the auth JWKS fetch path |
| 12 | +root_cause: wrong_api |
| 13 | +resolution_type: code_fix |
| 14 | +severity: high |
| 15 | +tags: |
| 16 | + - auth |
| 17 | + - env |
| 18 | + - convex |
| 19 | + - bootstrap |
| 20 | + - windows |
| 21 | + - bun |
| 22 | +--- |
| 23 | + |
| 24 | +# local auth env sync must use the real Convex CLI entrypoint |
| 25 | + |
| 26 | +## Problem |
| 27 | + |
| 28 | +Auth env sync already had the right lifecycle shape: prepare |
| 29 | +`BETTER_AUTH_SECRET`, then fetch `JWKS` after the generated auth runtime is |
| 30 | +live. |
| 31 | + |
| 32 | +But the actual command runner for `env push` was still using the local |
| 33 | +`convex` bin shim, while the rest of the CLI already used |
| 34 | +`node <real convex/bin/main.js>`. That split made auth bootstrap |
| 35 | +runtime-sensitive. |
| 36 | + |
| 37 | +## Symptoms |
| 38 | + |
| 39 | +- `kitcn add auth --yes` can reach the final JWKS fetch, print returned key |
| 40 | + data, then still fail the command. |
| 41 | +- `kitcn dev --bootstrap` can fail on the same auth env sync leg after the |
| 42 | + backend reports ready. |
| 43 | +- Platform/runtime combos that shell through Bun on Windows can crash after the |
| 44 | + child command closes, even though the auth function returned usable output. |
| 45 | + |
| 46 | +## What Didn't Work |
| 47 | + |
| 48 | +- Treating the returned JWKS payload as the bug. |
| 49 | + The payload shape was fine for kitcn's auth config flow. |
| 50 | +- Blaming auth generation or Better Auth runtime wiring first. |
| 51 | + Fresh Start repros on mac passed cleanly once the command path behaved. |
| 52 | +- Letting env sync keep its own Convex invocation style. |
| 53 | + That kept the most platform-sensitive callsite off the hardened runner path |
| 54 | + already used elsewhere in the CLI. |
| 55 | + |
| 56 | +## Solution |
| 57 | + |
| 58 | +Make `runLocalConvexCommand(...)` execute the real Convex CLI entrypoint |
| 59 | +through Node instead of the local `convex` bin wrapper. |
| 60 | + |
| 61 | +Before: |
| 62 | + |
| 63 | +```ts |
| 64 | +await execa("convex", args, { |
| 65 | + cwd: options.cwd, |
| 66 | + localDir: options.cwd, |
| 67 | + preferLocal: true, |
| 68 | + reject: false, |
| 69 | +}); |
| 70 | +``` |
| 71 | + |
| 72 | +After: |
| 73 | + |
| 74 | +```ts |
| 75 | +await execa("node", [REAL_CONVEX_CLI_PATH, ...args], { |
| 76 | + cwd: options.cwd, |
| 77 | + reject: false, |
| 78 | + stdio: "pipe", |
| 79 | +}); |
| 80 | +``` |
| 81 | + |
| 82 | +This makes auth env sync use the same Convex execution shape as |
| 83 | +`createBackendAdapter(...)` and `runBackendFunction(...)`. |
| 84 | + |
| 85 | +## Why This Works |
| 86 | + |
| 87 | +The auth flow itself was not the unstable part. The unstable part was using two |
| 88 | +different ways to launch Convex commands inside the same CLI: |
| 89 | + |
| 90 | +1. backend-core paths used `node <real convex/bin/main.js>` |
| 91 | +2. env sync used the local `convex` bin wrapper |
| 92 | + |
| 93 | +On friendly setups both work. On touchier runtime/platform combinations, |
| 94 | +especially Bun on Windows, the wrapper path can die after emitting usable |
| 95 | +stdout. Moving env sync onto the same Node-driven entrypoint removes that |
| 96 | +split-brain behavior. |
| 97 | + |
| 98 | +## Prevention |
| 99 | + |
| 100 | +- Keep local Convex calls on one execution path across `env`, `dev`, `add`, |
| 101 | + and backend helpers. |
| 102 | +- Add regression coverage for the command shape, not just the parsed output. |
| 103 | +- If a child command returns valid stdout but still exits non-zero, inspect the |
| 104 | + launcher first before rewriting the higher-level auth flow. |
| 105 | + |
| 106 | +## Related Issues |
| 107 | + |
| 108 | +- [auth-env-push-must-be-auth-aware-and-dev-bootstrap-must-stay-two-phase-20260324](/Users/zbeyens/git/better-convex/docs/solutions/integration-issues/auth-env-push-must-be-auth-aware-and-dev-bootstrap-must-stay-two-phase-20260324.md) |
| 109 | +- [dev-local-preflight-must-auto-upgrade-local-convex-backend-20260410](/Users/zbeyens/git/better-convex/docs/solutions/integration-issues/dev-local-preflight-must-auto-upgrade-local-convex-backend-20260410.md) |
0 commit comments