Source: Sentry preview environment, 2026-09-05 23:50–23:58Z, release 363e074 (363e074ca 2026-09-06T04:55:35+05:30 chore(booking): the two refunding sweeps are gated in DEGRADED maintenance), consultant profile e7f961b1…, scheduleType CUSTOM, browser in Asia/Calcutta. Four client captures of Error: Failed to update settings (FAMILIARISE_WEB-2T, op SettingsTab.save, expected:false) and one TypeError: Failed to fetch on the retry (FAMILIARISE_WEB-2S).
What the code does. app/dashboard/consultant/[consultantId]/(features)/settings/SettingsTab.tsx (~L484-486) checks only response.ok and throws a bodiless Error("Failed to update settings"), so whatever the PUT /api/user/consultants/[id] route answered (status, error, code) never reaches the consultant, the toast, or Sentry. The same page also swallows the retry's network failure as a generic message.
What the evidence rules out. The earlier hypothesis posted on #1512 (a 400 UTC_OFFSET_CONFLICT from resolveWeeklyUtcOffsetMinutes) is not supported: the client never sends utcOffsetMinutes (zero occurrences in SettingsTab.tsx and utils/schedule/formatting.ts both at 363e074 and on dev), so callerSupplied is always null and the conflict branch cannot fire from this page. The only server-side signal in the same trace (0a33363d…) is the intentional once-per-write warning "weekly availability written outside Asia/Kolkata", and the sampled PUT span in that trace answered 200 in 5.2 s. The failing responses themselves were not sampled (client_sample_rate 0.1), so their status is unknown; a 5-second happy-path save under PG_POOL_MAX=1 makes a Netlify function timeout on the slower attempts the leading suspect, but that is inference, not evidence.
Fix. Read the response body on !response.ok and surface error/code (and the HTTP status) in the thrown error and the toast, and attach them as Sentry extras; treat a business code as expected: true. Separately, measure the PUT's duration for a consultant with both weekly and custom rows and, if it is routinely multi-second, batch the row writes (one createMany per table inside the transaction) so the save cannot approach the function ceiling.
Band: post-mvp (no money path; the save works when the function answers in time). Related: #1522 (same 2026-09-06 pass, other pages), #872 (DST/zone follow-up), #1512 (merged; the comment there is superseded by this issue).
Source: Sentry preview environment, 2026-09-05 23:50–23:58Z, release 363e074 (
363e074ca 2026-09-06T04:55:35+05:30 chore(booking): the two refunding sweeps are gated in DEGRADED maintenance), consultant profile e7f961b1…, scheduleType CUSTOM, browser in Asia/Calcutta. Four client captures ofError: Failed to update settings(FAMILIARISE_WEB-2T, opSettingsTab.save, expected:false) and oneTypeError: Failed to fetchon the retry (FAMILIARISE_WEB-2S).What the code does.
app/dashboard/consultant/[consultantId]/(features)/settings/SettingsTab.tsx(~L484-486) checks onlyresponse.okand throws a bodilessError("Failed to update settings"), so whatever the PUT/api/user/consultants/[id]route answered (status,error,code) never reaches the consultant, the toast, or Sentry. The same page also swallows the retry's network failure as a generic message.What the evidence rules out. The earlier hypothesis posted on #1512 (a 400
UTC_OFFSET_CONFLICTfromresolveWeeklyUtcOffsetMinutes) is not supported: the client never sendsutcOffsetMinutes(zero occurrences inSettingsTab.tsxandutils/schedule/formatting.tsboth at 363e074 and on dev), socallerSuppliedis always null and the conflict branch cannot fire from this page. The only server-side signal in the same trace (0a33363d…) is the intentional once-per-write warning "weekly availability written outside Asia/Kolkata", and the sampled PUT span in that trace answered 200 in 5.2 s. The failing responses themselves were not sampled (client_sample_rate 0.1), so their status is unknown; a 5-second happy-path save underPG_POOL_MAX=1makes a Netlify function timeout on the slower attempts the leading suspect, but that is inference, not evidence.Fix. Read the response body on
!response.okand surfaceerror/code(and the HTTP status) in the thrown error and the toast, and attach them as Sentry extras; treat a business code asexpected: true. Separately, measure the PUT's duration for a consultant with both weekly and custom rows and, if it is routinely multi-second, batch the row writes (onecreateManyper table inside the transaction) so the save cannot approach the function ceiling.Band: post-mvp (no money path; the save works when the function answers in time). Related: #1522 (same 2026-09-06 pass, other pages), #872 (DST/zone follow-up), #1512 (merged; the comment there is superseded by this issue).