fix: tolerate a missing /api/i18n endpoint during bootstrap - #14501
Conversation
Backends that vendor no custom-node locale files do not implement /api/i18n, so the unconditional bootstrap call rejects with a 404. useAsyncState forwards that to globalThis.reportError, surfacing an unhandled AxiosError in every session. Treat a 404 as "no custom-node translations" and skip the merge; every other failure still sets i18nError.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 22 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Comment |
📄 Knowledge reviewDosu skipped reviewing this PR because your organization has used its |
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1782 passed, 0 failed📊 Browser Reports
📦 Bundle: 8.19 MB gzip 🔴 +162 BDetailsSummary
Category Glance App Entry Points — 3.62 kB (baseline 3.62 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.29 MB (baseline 1.29 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed / 1 unchanged Views & Navigation — 111 kB (baseline 111 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces Status: 16 unchanged Panels & Settings — 551 kB (baseline 551 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens Status: 26 unchanged User & Accounts — 28.7 kB (baseline 28.7 kB) • ⚪ 0 BAuthentication, profile, and account management bundles Status: 10 unchanged Editors & Dialogs — 124 kB (baseline 124 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors Status: 7 unchanged UI Components — 70 kB (baseline 70 kB) • ⚪ 0 BReusable component library chunks Status: 15 unchanged Data & Services — 3.44 MB (baseline 3.44 MB) • ⚪ 0 BStores, services, APIs, and repositories Status: 17 unchanged Utilities & Hooks — 386 kB (baseline 386 kB) • 🔴 +394 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed / 35 unchanged Vendor & Third-Party — 15.7 MB (baseline 15.7 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 16 unchanged Other — 12.7 MB (baseline 12.7 MB) • ⚪ 0 BBundles that do not match a named category
Status: 1 added / 1 removed / 279 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-07-31T20:28:50.614Z",
"gitSha": "107a3cddfe4025bdb205da5f4f504180c932eda9",
"branch": "matt/fe-1460-i18n-404-tolerance",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2087.813000000011,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.208000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 534.9569999999999,
"heapDeltaBytes": 5252472,
"heapUsedBytes": 73233244,
"domNodes": 18,
"jsHeapTotalBytes": 20049920,
"scriptDurationMs": 21.094,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-idle",
"durationMs": 2031.881999999996,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.688,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 458.658,
"heapDeltaBytes": 4662888,
"heapUsedBytes": 72587836,
"domNodes": 18,
"jsHeapTotalBytes": 20574208,
"scriptDurationMs": 15.559,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2036.1380000000224,
"styleRecalcs": 77,
"styleRecalcDurationMs": 45.467,
"layouts": 12,
"layoutDurationMs": 3.6470000000000002,
"taskDurationMs": 1067.407,
"heapDeltaBytes": -16153084,
"heapUsedBytes": 51695680,
"domNodes": -283,
"jsHeapTotalBytes": 21749760,
"scriptDurationMs": 143.783,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1861.139000000037,
"styleRecalcs": 74,
"styleRecalcDurationMs": 39.30799999999999,
"layouts": 12,
"layoutDurationMs": 3.3749999999999996,
"taskDurationMs": 890.6399999999999,
"heapDeltaBytes": -15308488,
"heapUsedBytes": 52475864,
"domNodes": -281,
"jsHeapTotalBytes": 20963328,
"scriptDurationMs": 123.099,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1733.6030000000164,
"styleRecalcs": 31,
"styleRecalcDurationMs": 17.105,
"layouts": 6,
"layoutDurationMs": 0.624,
"taskDurationMs": 375.31199999999995,
"heapDeltaBytes": 7999212,
"heapUsedBytes": 75774808,
"domNodes": 76,
"jsHeapTotalBytes": 20049920,
"scriptDurationMs": 19.523000000000003,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1724.3939999999611,
"styleRecalcs": 30,
"styleRecalcDurationMs": 16.746999999999996,
"layouts": 6,
"layoutDurationMs": 0.689,
"taskDurationMs": 381.73199999999997,
"heapDeltaBytes": 7781716,
"heapUsedBytes": 75482672,
"domNodes": 76,
"jsHeapTotalBytes": 20312064,
"scriptDurationMs": 21.366000000000003,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 662.9489999999691,
"styleRecalcs": 11,
"styleRecalcDurationMs": 10.017000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 428.78400000000005,
"heapDeltaBytes": -12191832,
"heapUsedBytes": 55398332,
"domNodes": 18,
"jsHeapTotalBytes": 22409216,
"scriptDurationMs": 65.36900000000001,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 582.8290000000607,
"styleRecalcs": 12,
"styleRecalcDurationMs": 8.66,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 382.367,
"heapDeltaBytes": -12217484,
"heapUsedBytes": 55610104,
"domNodes": 20,
"jsHeapTotalBytes": 21622784,
"scriptDurationMs": 58.108999999999995,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "large-graph-idle",
"durationMs": 2028.04900000001,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.9570000000000025,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 713.425,
"heapDeltaBytes": 7962092,
"heapUsedBytes": 66727740,
"domNodes": -282,
"jsHeapTotalBytes": 4517888,
"scriptDurationMs": 117.865,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2027.511000000004,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.637,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 677.845,
"heapDeltaBytes": 5432464,
"heapUsedBytes": 64346972,
"domNodes": -282,
"jsHeapTotalBytes": 4780032,
"scriptDurationMs": 105.601,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2182.988000000023,
"styleRecalcs": 69,
"styleRecalcDurationMs": 14.643999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1323.976,
"heapDeltaBytes": 5200560,
"heapUsedBytes": 65552380,
"domNodes": -284,
"jsHeapTotalBytes": 5005312,
"scriptDurationMs": 442.182,
"eventListeners": -142,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2203.2159999999976,
"styleRecalcs": 68,
"styleRecalcDurationMs": 13.291,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1320.123,
"heapDeltaBytes": 5279416,
"heapUsedBytes": 65673464,
"domNodes": -285,
"jsHeapTotalBytes": 5529600,
"scriptDurationMs": 440.818,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3245.383000000004,
"styleRecalcs": 64,
"styleRecalcDurationMs": 13.946,
"layouts": 60,
"layoutDurationMs": 7.386,
"taskDurationMs": 1506.8010000000002,
"heapDeltaBytes": 23938148,
"heapUsedBytes": 85871476,
"domNodes": 10,
"jsHeapTotalBytes": 7602176,
"scriptDurationMs": 540.8349999999999,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3214.902000000052,
"styleRecalcs": 65,
"styleRecalcDurationMs": 14.744999999999997,
"layouts": 60,
"layoutDurationMs": 7.166,
"taskDurationMs": 1522.082,
"heapDeltaBytes": -1428604,
"heapUsedBytes": 59672548,
"domNodes": -286,
"jsHeapTotalBytes": 7663616,
"scriptDurationMs": 531.921,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "minimap-idle",
"durationMs": 2051.9009999999867,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.972000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 690.8480000000002,
"heapDeltaBytes": 8603328,
"heapUsedBytes": 69240828,
"domNodes": -282,
"jsHeapTotalBytes": 4517888,
"scriptDurationMs": 104.944,
"eventListeners": -146,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2038.6680000000297,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.911999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 668.395,
"heapDeltaBytes": 8528540,
"heapUsedBytes": 69247924,
"domNodes": -283,
"jsHeapTotalBytes": 3993600,
"scriptDurationMs": 104.933,
"eventListeners": -142,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 593.496000000016,
"styleRecalcs": 47,
"styleRecalcDurationMs": 11.027000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 402.437,
"heapDeltaBytes": -11366804,
"heapUsedBytes": 56492792,
"domNodes": 20,
"jsHeapTotalBytes": 21884928,
"scriptDurationMs": 119.62900000000002,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 591.2839999999733,
"styleRecalcs": 47,
"styleRecalcDurationMs": 11.697999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 402.25700000000006,
"heapDeltaBytes": -11766812,
"heapUsedBytes": 56196196,
"domNodes": 20,
"jsHeapTotalBytes": 21884928,
"scriptDurationMs": 121.26,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-idle",
"durationMs": 2000.585000000001,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.563,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 509.207,
"heapDeltaBytes": 4419348,
"heapUsedBytes": 72376980,
"domNodes": 18,
"jsHeapTotalBytes": 21098496,
"scriptDurationMs": 16.878000000000004,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2020.762999999988,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.172999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 502.425,
"heapDeltaBytes": -20620224,
"heapUsedBytes": 47246904,
"domNodes": -279,
"jsHeapTotalBytes": 20963328,
"scriptDurationMs": 14.469999999999999,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1728.227000000004,
"styleRecalcs": 77,
"styleRecalcDurationMs": 40.428,
"layouts": 16,
"layoutDurationMs": 4.111,
"taskDurationMs": 789.286,
"heapDeltaBytes": -4907288,
"heapUsedBytes": 63187276,
"domNodes": 66,
"jsHeapTotalBytes": 21360640,
"scriptDurationMs": 95.97699999999999,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1732.7889999999115,
"styleRecalcs": 76,
"styleRecalcDurationMs": 35.373000000000005,
"layouts": 16,
"layoutDurationMs": 3.8389999999999995,
"taskDurationMs": 818.5160000000001,
"heapDeltaBytes": -20490304,
"heapUsedBytes": 47509856,
"domNodes": -280,
"jsHeapTotalBytes": 20701184,
"scriptDurationMs": 91.11800000000001,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1417.6680000000488,
"styleRecalcs": 19,
"styleRecalcDurationMs": 31.411999999999995,
"layouts": 15,
"layoutDurationMs": 12.558,
"taskDurationMs": 933.7280000000001,
"heapDeltaBytes": 3852468,
"heapUsedBytes": 74839680,
"domNodes": 13673,
"jsHeapTotalBytes": 15728640,
"scriptDurationMs": 34.32800000000001,
"eventListeners": 2371,
"totalBlockingTimeMs": 139,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "viewport-pan-sweep",
"durationMs": 8458.503000000008,
"styleRecalcs": 250,
"styleRecalcDurationMs": 38.27700000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4792.267,
"heapDeltaBytes": 12204664,
"heapUsedBytes": 71232500,
"domNodes": -280,
"jsHeapTotalBytes": 6545408,
"scriptDurationMs": 1462.6919999999998,
"eventListeners": -126,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8281.466000000022,
"styleRecalcs": 250,
"styleRecalcDurationMs": 37.26599999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4542.410999999999,
"heapDeltaBytes": 11711876,
"heapUsedBytes": 70391012,
"domNodes": -281,
"jsHeapTotalBytes": 7069696,
"scriptDurationMs": 1390.56,
"eventListeners": -128,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 17482.72300000002,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17442.048,
"heapDeltaBytes": -42723940,
"heapUsedBytes": 180020496,
"domNodes": -8312,
"jsHeapTotalBytes": -14618624,
"scriptDurationMs": 594.6170000000001,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17326.729,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17300.387000000002,
"heapDeltaBytes": -56400940,
"heapUsedBytes": 167747088,
"domNodes": -8312,
"jsHeapTotalBytes": -13836288,
"scriptDurationMs": 578.7860000000001,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21480.475000000013,
"styleRecalcs": 151,
"styleRecalcDurationMs": 18.038999999999973,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21414.136,
"heapDeltaBytes": -29970776,
"heapUsedBytes": 178602260,
"domNodes": -8312,
"jsHeapTotalBytes": -13643776,
"scriptDurationMs": 918.664,
"eventListeners": -16385,
"totalBlockingTimeMs": 284,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21394.535000000018,
"styleRecalcs": 146,
"styleRecalcDurationMs": 17.861000000000015,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21336.403,
"heapDeltaBytes": -48460788,
"heapUsedBytes": 180010828,
"domNodes": -8312,
"jsHeapTotalBytes": -16265216,
"scriptDurationMs": 912.2379999999999,
"eventListeners": -16381,
"totalBlockingTimeMs": 406,
"frameDurationMs": 18.330000000000048,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 107.89299999999002,
"styleRecalcs": 10,
"styleRecalcDurationMs": 15.619000000000002,
"layouts": 2,
"layoutDurationMs": 0.31799999999999995,
"taskDurationMs": 82.15499999999999,
"heapDeltaBytes": 3271708,
"heapUsedBytes": 70358100,
"domNodes": 119,
"jsHeapTotalBytes": 3145728,
"scriptDurationMs": 7.531999999999997,
"eventListeners": 33,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "workflow-execution",
"durationMs": 475.3299999999854,
"styleRecalcs": 10,
"styleRecalcDurationMs": 17.087,
"layouts": 3,
"layoutDurationMs": 0.6699999999999998,
"taskDurationMs": 109.76799999999999,
"heapDeltaBytes": -16033936,
"heapUsedBytes": 51031236,
"domNodes": 115,
"jsHeapTotalBytes": 7467008,
"scriptDurationMs": 9.611999999999998,
"eventListeners": 65,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
There was a problem hiding this comment.
🔍 Cursor Review — Consolidated panel
Triggered by @mattmillerai.
Every reviewer in the matrix failed to contribute — see the panel summary for which cells errored, and the run logs for the underlying cause.
Panel: 0/8 reviewers contributed findings.
Reviewers that did not contribute: claude-opus-4-8-thinking-max:adversarial (error), gemini-3.1-pro:adversarial (error), gpt-5.6-sol-max:adversarial (error), kimi-k2.7-code:adversarial (error), claude-opus-4-8-thinking-max:edge-case (error), gemini-3.1-pro:edge-case (error), gpt-5.6-sol-max:edge-case (error), kimi-k2.7-code:edge-case (error)
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #14501 +/- ##
=======================================
Coverage 79.35% 79.35%
=======================================
Files 1767 1767
Lines 113935 113940 +5
Branches 36681 36598 -83
=======================================
+ Hits 90414 90419 +5
+ Misses 22982 22978 -4
- Partials 539 543 +4
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 7 files with indirect coverage changes 🚀 New features to boost your workflow:
|
huang47
left a comment
There was a problem hiding this comment.
lgtm based on the criteria
/api/i18n, so a 404 means "no custom-node translations", not a failure."
|
@mattmillerai Successfully backported to #15176 |
|
@mattmillerai Successfully backported to #15177 |
ELI-5
Every time the app starts it asks the server "do any custom nodes ship translations?". Some backends deliberately don't have that endpoint at all, so the browser gets a 404 back — and because nobody was catching it, that 404 turned into a big red unhandled error in the console (and in error tracking) even though nothing was actually broken. Now we treat "endpoint isn't there" as "there are no custom-node translations", and carry on. Real failures still get reported.
Summary
bootstrapStorecalledapi.getCustomNodesI18n()unconditionally with no rejection handling. On a backend that does not implementGET /api/i18n(Cloud vendors no custom-node locale files, so the endpoint is intentionally absent), the request 404s and the resultingAxiosErrorreachesuseAsyncState's defaultonError, which isglobalThis.reportError— i.e. it surfaces as an unhandled error towindow.onerrorand to RUM. In production this fires in ~1,300 distinct sessions/week (2,406 events over a rolling 7 days), mostly on the login view before the user has even signed in.Changes
bootstrapStorenow routes the fetch through a smallfetchCustomNodesI18n()helper that swallows only an Axios 404 and returnsundefined; everything else is rethrown unchanged and still lands ini18nError. When the endpoint is absent,mergeCustomNodesI18nis skipped and bootstrap proceeds.src/stores/bootstrapStore.test.tsgains a 404 case (assertsisI18nReadyflips true,i18nErrorstays undefined, merge is skipped) and a 500 case (asserts the error is still surfaced). Confirmed the 404 test fails against the unpatched store and passes with the fix; the 500 test passes either way, which is the point — it is the guard against blanket-swallowing.Review Focus
mergeCustomNodesI18nrather than calling it with{}. That is deliberate:mergeCustomNodesI18nclearscustomNodesI18nDatabefore assigning, so passing an empty map would wipe any previously merged custom-node translations on a re-run rather than being a no-op.ComfyApi.getCustomNodesI18n, so the transport method stays faithful to the response and any future caller can still distinguish a 404.getCustomNodesI18ncurrently has exactly one call site.error.responseis undefined for the latter, so it rethrows) are unchanged and still reported.Verification
vitest run src/stores/bootstrapStore.test.ts src/i18n.test.ts(23 passed),eslintandoxfmtclean on both changed files. Full-repovue-tscwas run but is not a usable signal in this worktree — it borrows the parent clone'snode_modulesvia symlink, which breaks SFC type-reference resolution and produces ~1,400 pre-existing.vuediagnostics unrelated to this change. No diagnostics were reported for any file undersrc/stores/, including both changed files. Relying on CI for the whole-repo typecheck gate.Provenance
This came out of a goal run against the Cloud frontend error-free-sessions dashboard ("State of Dog", Datadog RUM, prod), measured over a rolling 7-day window: error-free sessions were sitting at 17–22% daily, with 8,662 of 10,790 sessions containing at least one error. The target is ≥90% daily, and this 404 was the single highest-session-count contributor. The endpoint's absence was confirmed server-side (it is tagged local-only and has no handler) before writing the fix, so this is deliberately a frontend-side tolerance rather than a request to implement the endpoint.