Commit 651700b
fix(web): restore ServiceError boundary in
* fix(web): restore ServiceError boundary in `getFileSourceForRepo`
## Problem
In v4.16.14 (PR #1104, GitLab MR Review Agent), the core file-fetch logic was
extracted from inside `sew()` into a standalone `getFileSourceForRepo` function
so it could be called by privileged server-side callers (e.g. the review agent
webhook handler) without going through the auth middleware.
The extraction introduced a missing error boundary. The catch block inside
`getFileSourceForRepo` handled two known git error patterns and **re-threw
everything else**:
```ts
// getFileSourceApi.ts — before this fix
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error);
if (errorMessage.includes('does not exist') || ...) return fileNotFound(...);
if (errorMessage.includes('unknown revision') || ...) return unexpectedError(...);
throw error; // ← propagates uncaught; sew() no longer wraps this code path
}
```
Because `getFileSourceForRepo` is no longer inside `sew()`, any re-thrown
exception escapes as a fatal error through the Next.js server task runner,
producing the `z.onFatalException` / `z.attemptTask` stack trace seen in
production on v4.16.14.
A second contributing factor: the review agent was also changed in v4.16.14 to
pass `ref: pr_payload.head_sha` where `ref` was previously `undefined`. If the
bare clone hasn't fetched that commit yet, `git show` throws with
`"unknown revision"` — which fell into the same unhandled re-throw path.
Rolling back to v4.16.13 restored the original `sew()`-wrapped code path, which
is why the rollback fixed the issue.
## Fix
Two targeted changes in `getFileSourceApi.ts`:
1. **`throw error` → `return unexpectedError(errorMessage)`** — ensures
`getFileSourceForRepo` always returns `FileSourceResponse | ServiceError`
and never rejects its promise. This is the root-cause fix.
2. **`unexpectedError(...)` → `invalidGitRef(gitRef)`** for the
`"unknown revision"` / `"bad revision"` / `"invalid object name"` branch —
uses the semantically correct error type (already imported), which also
gives callers a more actionable error when `head_sha` hasn't been fetched.
## Tests
Added `getFileSourceApi.test.ts` with 19 tests covering:
- **Repository validation** — `NOT_FOUND` when repo is absent from the DB;
correct `findFirst` query shape.
- **Input validation** — path traversal and null-byte paths → `FILE_NOT_FOUND`;
refs starting with `-` → `INVALID_GIT_REF` (flag-injection guard).
- **Git error handling** (the regression suite):
- `"does not exist"` / `"fatal: path"` → `FILE_NOT_FOUND`
- `"unknown revision"` (unfetched `head_sha`) → `INVALID_GIT_REF`
- `"bad revision"` / `"invalid object name"` → `INVALID_GIT_REF`
- **Unrecognised error → `UNEXPECTED_ERROR`, not a throw** — explicit
regression test; before the fix, `.resolves` would fail because the
promise rejected.
- **Successful response** — source content, language, ref fallback chain
(`ref` → `defaultBranch` → `HEAD`), correct `cwd` path.
- **Language detection** — prefers `.gitattributes`; falls back to
filename-based detection when the file is absent.
## Files changed
| File | Change |
|------|--------|
| `packages/web/src/features/git/getFileSourceApi.ts` | `throw error` → `return unexpectedError(errorMessage)`; invalid-ref branch now returns `invalidGitRef(gitRef)` |
| `packages/web/src/features/git/getFileSourceApi.test.ts` | New — 19 tests |
* fix(web): harden getFileSourceForRepo error boundary
Three fixes to getFileSourceForRepo, which was extracted outside sew()
in v4.16.14 and lost its error boundary:
- Wrap the entire function body in a top-level try/catch so exceptions
from prisma, getRepoPath, simpleGit().cwd(), language helpers, and URL
builders are converted to unexpectedError rather than propagating as
fatal Next.js task-runner exceptions.
- Add unresolvedGitRef() to serviceError.ts (errorCode: INVALID_GIT_REF,
distinct message) and use it for "unknown revision"/"bad revision"/
"invalid object name" git errors, replacing the syntactic invalidGitRef
message that was misleading for unfetched head_sha refs.
- Fix the simple-git vi.mock() factory in the test file to map both the
default and named exports to the same hoisted mock fn, ensuring the SUT
and the test body reference identical mocks. Add a test for the outer
catch (DB throws) and tighten INVALID_GIT_REF assertions to distinguish
syntactic from unresolved-ref errors by message content.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add CHANGELOG entry
* refactor(web): use sew() instead of bare try/catch in getFileSourceForRepo
The top-level try/catch added to getFileSourceForRepo silently swallowed
unexpected errors with no Sentry capture or log entry. Replace it with
sew(), which provides the same ServiceError conversion plus Sentry
reporting and structured logging.
The inner git-specific catch is preserved unchanged — sew() only handles
anything that escapes it (DB errors, getRepoPath, URL builders, etc.).
Update the sew mock in the test file to catch and convert exceptions,
matching the real sew() behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Gavin Williams <gavin.williams@getchip.uk>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>getFileSourceForRepo (#1145)1 parent d111397 commit 651700b
4 files changed
Lines changed: 382 additions & 5 deletions
File tree
- packages/web/src
- features/git
- lib
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
10 | 13 | | |
11 | 14 | | |
12 | 15 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
0 commit comments