Skip to content

Commit 8a43f85

Browse files
fix: handle failed global subgraph blueprint loading gracefully
- Throw on API failure in getGlobalSubgraphData instead of returning '' - Validate global blueprint data is non-empty before loading - Propagate individual global blueprint errors to toast/console reporting - Improve assertion messages with file path context Amp-Thread-ID: https://ampcode.com/threads/T-019c7e5b-2255-73d8-bda5-a3608d313f14
1 parent 8f48b11 commit 8a43f85

File tree

4 files changed

+92
-9
lines changed

4 files changed

+92
-9
lines changed

src/platform/workflow/management/stores/comfyWorkflow.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,13 @@ export class ComfyWorkflow extends UserFile {
106106
await super.load({ force })
107107
if (!force && this.isLoaded) return this as this & LoadedComfyWorkflow
108108

109-
if (!this.originalContent) {
110-
throw new Error('[ASSERT] Workflow content should be loaded')
109+
if (this.originalContent == null) {
110+
throw new Error(
111+
`[ASSERT] Workflow content should be loaded for '${this.path}'`
112+
)
113+
}
114+
if (this.originalContent.trim().length === 0) {
115+
throw new Error(`Workflow content is empty for '${this.path}'`)
111116
}
112117

113118
const initialState = JSON.parse(this.originalContent)

src/scripts/api.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,9 +1181,16 @@ export class ComfyApi extends EventTarget {
11811181

11821182
async getGlobalSubgraphData(id: string): Promise<string> {
11831183
const resp = await api.fetchApi('/global_subgraphs/' + id)
1184-
if (resp.status !== 200) return ''
1184+
if (resp.status !== 200) {
1185+
throw new Error(
1186+
`Failed to fetch global subgraph '${id}': ${resp.status} ${resp.statusText}`
1187+
)
1188+
}
11851189
const subgraph: GlobalSubgraphData = await resp.json()
1186-
return subgraph?.data ?? ''
1190+
if (!subgraph?.data) {
1191+
throw new Error(`Global subgraph '${id}' returned empty data`)
1192+
}
1193+
return subgraph.data as string
11871194
}
11881195
async getGlobalSubgraphs(): Promise<Record<string, GlobalSubgraphData>> {
11891196
const resp = await api.fetchApi('/global_subgraphs')

src/stores/subgraphStore.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,68 @@ describe('useSubgraphStore', () => {
225225
})
226226
})
227227

228+
it('should handle global blueprint with empty data gracefully', async () => {
229+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
230+
await mockFetch(
231+
{},
232+
{
233+
broken_blueprint: {
234+
name: 'Broken Blueprint',
235+
info: { node_pack: 'test_pack' },
236+
data: ''
237+
}
238+
}
239+
)
240+
expect(consoleSpy).toHaveBeenCalledWith(
241+
'Failed to load subgraph blueprint',
242+
expect.any(Error)
243+
)
244+
expect(store.subgraphBlueprints).toHaveLength(0)
245+
consoleSpy.mockRestore()
246+
})
247+
248+
it('should handle global blueprint with rejected data promise gracefully', async () => {
249+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
250+
await mockFetch(
251+
{},
252+
{
253+
failing_blueprint: {
254+
name: 'Failing Blueprint',
255+
info: { node_pack: 'test_pack' },
256+
data: Promise.reject(new Error('Network error')) as unknown as string
257+
}
258+
}
259+
)
260+
expect(consoleSpy).toHaveBeenCalledWith(
261+
'Failed to load subgraph blueprint',
262+
expect.any(Error)
263+
)
264+
expect(store.subgraphBlueprints).toHaveLength(0)
265+
consoleSpy.mockRestore()
266+
})
267+
268+
it('should load valid global blueprints even when others fail', async () => {
269+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
270+
await mockFetch(
271+
{},
272+
{
273+
broken: {
274+
name: 'Broken',
275+
info: { node_pack: 'test_pack' },
276+
data: ''
277+
},
278+
valid: {
279+
name: 'Valid Blueprint',
280+
info: { node_pack: 'test_pack' },
281+
data: JSON.stringify(mockGraph)
282+
}
283+
}
284+
)
285+
expect(consoleSpy).toHaveBeenCalled()
286+
expect(store.subgraphBlueprints).toHaveLength(1)
287+
consoleSpy.mockRestore()
288+
})
289+
228290
describe('search_aliases support', () => {
229291
it('should include search_aliases from workflow extra', async () => {
230292
const mockGraphWithAliases = {

src/stores/subgraphStore.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,19 @@ export const useSubgraphStore = defineStore('subgraph', () => {
198198
}
199199
async function loadInstalledBlueprints() {
200200
async function loadGlobalBlueprint([k, v]: [string, GlobalSubgraphData]) {
201+
const data = await v.data
202+
if (typeof data !== 'string' || data.trim().length === 0) {
203+
throw new Error(
204+
`Global blueprint '${v.name}' (${k}) returned empty content`
205+
)
206+
}
201207
const path = SubgraphBlueprint.basePath + v.name + '.json'
202208
const blueprint = new SubgraphBlueprint({
203209
path,
204210
modified: Date.now(),
205211
size: -1
206212
})
207-
blueprint.originalContent = blueprint.content = await v.data
213+
blueprint.originalContent = blueprint.content = data
208214
blueprint.filename = v.name
209215
useWorkflowStore().attachWorkflow(blueprint)
210216
const loaded = await blueprint.load()
@@ -238,16 +244,19 @@ export const useSubgraphStore = defineStore('subgraph', () => {
238244
return false
239245
return true
240246
})
241-
await Promise.allSettled(filteredEntries.map(loadGlobalBlueprint))
247+
return Promise.allSettled(filteredEntries.map(loadGlobalBlueprint))
242248
}
243249

244250
const userSubs = (
245251
await api.listUserDataFullInfo(SubgraphBlueprint.basePath)
246252
).filter((f) => f.path.endsWith('.json'))
247-
const settled = await Promise.allSettled([
248-
...userSubs.map(loadBlueprint),
249-
loadInstalledBlueprints()
253+
const [globalResult, ...userResults] = await Promise.allSettled([
254+
loadInstalledBlueprints(),
255+
...userSubs.map(loadBlueprint)
250256
])
257+
const globalResults =
258+
globalResult.status === 'fulfilled' ? globalResult.value : []
259+
const settled = [...globalResults, ...userResults]
251260

252261
const errors = settled.filter((i) => 'reason' in i).map((i) => i.reason)
253262
errors.forEach((e) => console.error('Failed to load subgraph blueprint', e))

0 commit comments

Comments
 (0)