[backport core/1.50] fix(errors): keep missing node packs across prompt submissions - #15513
Conversation
## Summary
Pressing Run emptied the missing-node-pack rows from the Errors tab; the
nodes were still missing, the panel just stopped saying so.
## Changes
- **What**: `clearAllErrors` was shared by `queuePrompt` ("forget the
last run") and `clean()` ("forget this graph"), and cleared missing-node
state for both. A submission carries no evidence about the environment —
it never checks whether the pack was installed — so it cannot justify
dropping the row. The clear moves to `clean()`, and the function is
renamed `clearRunErrors` to match what it now does.
Missing **model** and **media** state already followed this rule:
`clearAllErrors` never touched it, and it is cleared in `loadGraphData`
instead. This aligns missing nodes with the two resources that were
already right; it does not change when models or media are cleared.
Production change is four lines.
## Review Focus
**Every discard path still clears.** `clean()` is reached by
`loadGraphData`, `loadApiJson`, `Comfy.ClearWorkflow`
(`useCoreCommands.ts:279`) and the legacy Clear button (`ui.ts:680`).
**Except one, which needed the clear spelled out.** The A1111 import
replaces the graph from inside `importA1111` through a
`beforeGraphClear` callback and never reaches `clean()`, so it already
left the store describing the outgoing graph. That was survivable only
because the next submission happened to wipe it — with submissions no
longer clearing, the stale rows would persist indefinitely.
`afterLoadNewGraph` does not call `showPendingWarnings`, so nothing else
re-syncs that path. The callback runs after the parameters and required
core nodes validate, so a failed import keeps the current state.
**What this deliberately does not do.** An earlier version of this PR
generalised the same rule to the missing-model and missing-media stores.
It was abandoned: those two carry async verification that outlives the
graph that started it, plus a per-workflow cache and a two-tier repair
state, and unifying them produced five separate defects (cache
resurrection after discard, cache not synced on per-node removal,
verification not aborted, an abort whose signal was passed but never
checked after the await, and the A1111 bypass for all three resources).
None of that is in this PR. It is written up separately and will be its
own change.
## Verification
Four tests, each mutation-proved — revert the production line, watch the
named test fail, restore, watch it pass:
| mutation | fails |
|---|---|
| restore the clear inside `clearRunErrors` | `preserves missing node
packs when submitting a prompt`, store test, E2E |
| drop `clean()`'s clear | `clears missing node packs when the graph is
discarded` |
| drop the A1111 callback clear | `clears missing node packs, which its
graph swap skips clean() for` |
| drop `queuePrompt`'s `clearRunErrors()` | queue unit test |
The E2E (`errorsTabMissingNodes.spec.ts`) waits on the `POST
/api/prompt` response before re-asserting, so it observes the state
after the submit path has run rather than racing it.
`pnpm typecheck`, `pnpm typecheck:browser`, `pnpm lint` (0 errors),
`pnpm knip`, `pnpm format` all clean; 88 unit tests and the E2E pass.
Replaces #14557.
🎭 Playwright: ✅ 1801 passed, 0 failed · 2 flaky📊 Browser Reports
🎨 Storybook: ✅ Built — View Storybook📦 Bundle Size
⚡ Performance Report
✅ No regressions detected. All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-08-21T01:58:42.219Z",
"gitSha": "569680c6a5647fb08cc4e5a6749b2b850f13f6f1",
"branch": "backport-14900-to-core-1.50",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2017.325000000028,
"styleRecalcs": 10,
"styleRecalcDurationMs": 4.438000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 320.272,
"heapDeltaBytes": 5398728,
"heapUsedBytes": 69445548,
"domNodes": 20,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 10.937000000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-idle",
"durationMs": 2005.1529999999502,
"styleRecalcs": 12,
"styleRecalcDurationMs": 5.274999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 313.522,
"heapDeltaBytes": 5899664,
"heapUsedBytes": 70296900,
"domNodes": 24,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 10.446,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1759.9030000000084,
"styleRecalcs": 72,
"styleRecalcDurationMs": 24.78,
"layouts": 12,
"layoutDurationMs": 2.892,
"taskDurationMs": 640.126,
"heapDeltaBytes": -15531988,
"heapUsedBytes": 48833708,
"domNodes": -282,
"jsHeapTotalBytes": 24092672,
"scriptDurationMs": 78.836,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1686.113999999975,
"styleRecalcs": 73,
"styleRecalcDurationMs": 18.808000000000003,
"layouts": 12,
"layoutDurationMs": 1.8319999999999999,
"taskDurationMs": 508.874,
"heapDeltaBytes": -149828,
"heapUsedBytes": 64226592,
"domNodes": 58,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 60.63099999999999,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1688.5330000000067,
"styleRecalcs": 30,
"styleRecalcDurationMs": 10.683000000000002,
"layouts": 6,
"layoutDurationMs": 0.5059999999999999,
"taskDurationMs": 252.243,
"heapDeltaBytes": 8172980,
"heapUsedBytes": 72632680,
"domNodes": 79,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 12.345,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1714.112,
"styleRecalcs": 31,
"styleRecalcDurationMs": 10.838,
"layouts": 6,
"layoutDurationMs": 0.48699999999999993,
"taskDurationMs": 249.509,
"heapDeltaBytes": 8830720,
"heapUsedBytes": 73222608,
"domNodes": 77,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 12.249,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 475.49400000002606,
"styleRecalcs": 12,
"styleRecalcDurationMs": 4.370000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 256.97400000000005,
"heapDeltaBytes": -11608180,
"heapUsedBytes": 52874364,
"domNodes": 20,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 32.954,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 405.9349999999995,
"styleRecalcs": 13,
"styleRecalcDurationMs": 4.719000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 235.28300000000002,
"heapDeltaBytes": -12759432,
"heapUsedBytes": 51599508,
"domNodes": 22,
"jsHeapTotalBytes": 26214400,
"scriptDurationMs": 30.159000000000002,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "large-graph-idle",
"durationMs": 2007.6499999999555,
"styleRecalcs": 10,
"styleRecalcDurationMs": 5.705000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 480.77500000000003,
"heapDeltaBytes": 7814336,
"heapUsedBytes": 69791912,
"domNodes": -280,
"jsHeapTotalBytes": 2985984,
"scriptDurationMs": 57.733,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2009.115999999949,
"styleRecalcs": 10,
"styleRecalcDurationMs": 5.340999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 467.132,
"heapDeltaBytes": 4258224,
"heapUsedBytes": 66311260,
"domNodes": -280,
"jsHeapTotalBytes": 4034560,
"scriptDurationMs": 55.019,
"eventListeners": -177,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2058.622000000014,
"styleRecalcs": 68,
"styleRecalcDurationMs": 8.193000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 782.438,
"heapDeltaBytes": 20872984,
"heapUsedBytes": 82245144,
"domNodes": -277,
"jsHeapTotalBytes": 2916352,
"scriptDurationMs": 231.38600000000002,
"eventListeners": -177,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2052.045000000021,
"styleRecalcs": 69,
"styleRecalcDurationMs": 8.961,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 789.8839999999999,
"heapDeltaBytes": 19291552,
"heapUsedBytes": 82204084,
"domNodes": -280,
"jsHeapTotalBytes": 5013504,
"scriptDurationMs": 233.39300000000003,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3021.913999999981,
"styleRecalcs": 66,
"styleRecalcDurationMs": 9.790000000000001,
"layouts": 60,
"layoutDurationMs": 4.999999999999999,
"taskDurationMs": 898.8009999999999,
"heapDeltaBytes": 21814828,
"heapUsedBytes": 86172140,
"domNodes": 18,
"jsHeapTotalBytes": 6815744,
"scriptDurationMs": 290.97299999999996,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3090.69599999998,
"styleRecalcs": 66,
"styleRecalcDurationMs": 10.243999999999998,
"layouts": 60,
"layoutDurationMs": 5.539,
"taskDurationMs": 947.1250000000001,
"heapDeltaBytes": 22708468,
"heapUsedBytes": 86488060,
"domNodes": 14,
"jsHeapTotalBytes": 7340032,
"scriptDurationMs": 301.541,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2012.110000000007,
"styleRecalcs": 10,
"styleRecalcDurationMs": 5.232999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 488.394,
"heapDeltaBytes": 6782520,
"heapUsedBytes": 67835124,
"domNodes": -282,
"jsHeapTotalBytes": 4296704,
"scriptDurationMs": 58.727999999999994,
"eventListeners": -177,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "minimap-idle",
"durationMs": 2006.0649999999214,
"styleRecalcs": 9,
"styleRecalcDurationMs": 4.793999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 489.691,
"heapDeltaBytes": 6921956,
"heapUsedBytes": 67807060,
"domNodes": -282,
"jsHeapTotalBytes": 3510272,
"scriptDurationMs": 60.379000000000005,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 438.9840000000049,
"styleRecalcs": 48,
"styleRecalcDurationMs": 8.008000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 273.244,
"heapDeltaBytes": -10956868,
"heapUsedBytes": 53610376,
"domNodes": 22,
"jsHeapTotalBytes": 26214400,
"scriptDurationMs": 76.033,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 451.2609999999313,
"styleRecalcs": 47,
"styleRecalcDurationMs": 7.032999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 280.89599999999996,
"heapDeltaBytes": -10867084,
"heapUsedBytes": 53644380,
"domNodes": 20,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 76.11999999999999,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.669999999999998,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-idle",
"durationMs": 2005.3849999999898,
"styleRecalcs": 11,
"styleRecalcDurationMs": 5.443,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 340.441,
"heapDeltaBytes": 6015696,
"heapUsedBytes": 70364932,
"domNodes": 22,
"jsHeapTotalBytes": 24379392,
"scriptDurationMs": 10.473999999999998,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 1990.8320000000685,
"styleRecalcs": 11,
"styleRecalcDurationMs": 5.1259999999999994,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 330.909,
"heapDeltaBytes": 5411488,
"heapUsedBytes": 69789748,
"domNodes": 22,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 10.248999999999999,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1673.530000000028,
"styleRecalcs": 77,
"styleRecalcDurationMs": 20.221,
"layouts": 16,
"layoutDurationMs": 2.251,
"taskDurationMs": 479.83000000000004,
"heapDeltaBytes": -3782168,
"heapUsedBytes": 60692344,
"domNodes": 65,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 48.907000000000004,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1674.3149999999787,
"styleRecalcs": 76,
"styleRecalcDurationMs": 20.029,
"layouts": 16,
"layoutDurationMs": 2.242,
"taskDurationMs": 470.28599999999994,
"heapDeltaBytes": -3548248,
"heapUsedBytes": 60802056,
"domNodes": 64,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 48.28900000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 816.4020000000392,
"styleRecalcs": 20,
"styleRecalcDurationMs": 20.034999999999997,
"layouts": 16,
"layoutDurationMs": 7.378000000000001,
"taskDurationMs": 582.902,
"heapDeltaBytes": 30905348,
"heapUsedBytes": 96945228,
"domNodes": 13673,
"jsHeapTotalBytes": 16515072,
"scriptDurationMs": 16.852999999999994,
"eventListeners": 2375,
"totalBlockingTimeMs": 80,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "viewport-pan-sweep",
"durationMs": 8078.145999999947,
"styleRecalcs": 250,
"styleRecalcDurationMs": 21.951,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 2720.755,
"heapDeltaBytes": 9627520,
"heapUsedBytes": 71002040,
"domNodes": -276,
"jsHeapTotalBytes": 6586368,
"scriptDurationMs": 763.3259999999999,
"eventListeners": -131,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8092.084999999997,
"styleRecalcs": 250,
"styleRecalcDurationMs": 23.956,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 2843.208,
"heapDeltaBytes": 25573892,
"heapUsedBytes": 87553872,
"domNodes": -278,
"jsHeapTotalBytes": 5799936,
"scriptDurationMs": 793.1120000000001,
"eventListeners": -163,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 9285.18699999995,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 9182.102,
"heapDeltaBytes": -59760688,
"heapUsedBytes": 169686476,
"domNodes": -8312,
"jsHeapTotalBytes": -8331264,
"scriptDurationMs": 340.412,
"eventListeners": -16391,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 9225.529999999935,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 9193.078,
"heapDeltaBytes": -53367516,
"heapUsedBytes": 168797208,
"domNodes": -8312,
"jsHeapTotalBytes": -11210752,
"scriptDurationMs": 330.504,
"eventListeners": -16393,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333338,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-pan",
"durationMs": 12767.249999999989,
"styleRecalcs": 65,
"styleRecalcDurationMs": 13.53399999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 12723.813999999998,
"heapDeltaBytes": -56396980,
"heapUsedBytes": 157138368,
"domNodes": -8316,
"jsHeapTotalBytes": -8855552,
"scriptDurationMs": 652.729,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.220000000000073,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 11841.399000000023,
"styleRecalcs": 66,
"styleRecalcDurationMs": 12.752000000000013,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 11801.202,
"heapDeltaBytes": -45162740,
"heapUsedBytes": 167426436,
"domNodes": -8312,
"jsHeapTotalBytes": -11476992,
"scriptDurationMs": 614.642,
"eventListeners": -16389,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "workflow-execution",
"durationMs": 411.41700000002857,
"styleRecalcs": 14,
"styleRecalcDurationMs": 10.492,
"layouts": 3,
"layoutDurationMs": 0.374,
"taskDurationMs": 72.235,
"heapDeltaBytes": 5069516,
"heapUsedBytes": 68414560,
"domNodes": 128,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 5.802,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
},
{
"name": "workflow-execution",
"durationMs": 431.440000000066,
"styleRecalcs": 12,
"styleRecalcDurationMs": 8.968000000000002,
"layouts": 2,
"layoutDurationMs": 0.2769999999999999,
"taskDurationMs": 69.937,
"heapDeltaBytes": 5060788,
"heapUsedBytes": 68523368,
"domNodes": 123,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 6.119999999999999,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000273
}
]
} |
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## core/1.50 #15513 +/- ##
===========================================
Coverage 81.34% 81.34%
===========================================
Files 1872 1872
Lines 106289 106291 +2
Branches 32304 32773 +469
===========================================
+ Hits 86456 86458 +2
Misses 19478 19478
Partials 355 355
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Backport of #14900 to
core/1.50Automatically created by backport workflow.