Summary
On v1.17.1, we are seeing intermittent cases where a prompt reaches execution_success / completed, but comfyui-api immediately tries to read files listed in /history/{prompt_id} and some of them are not readable yet.
This produces warnings like:
Prompt executed in 0.05 seconds
{"msg":"Prompt <A> completed execution"}
{"msg":"Prompt <B> completed"}
{"msg":"Failed to read file /output/<B>_Subtitles_00001_.txt: ENOENT: no such file or directory"}
{"msg":"Failed to read file /output/<B>_Audio_00001_.mp3: ENOENT: no such file or directory"}
{"msg":"Failed to read file /output/<B>_synthetize_head_00001_.json: ENOENT: no such file or directory"}
Retrying the same request often succeeds.
Why this looks like a wrapper race condition
After reading the source for v1.17.1, the sequence seems to be:
runPromptAndGetOutputs() waits for either websocket completion or history polling.
- If websocket
execution_success wins, it logs Prompt <id> completed, then speeds up history polling to 30ms.
getPromptOutputs() fetches /history/{promptId}.
- If
status.completed === true, it iterates every history-listed output file and immediately does readFile(outputDir/filename).
- If
readFile() returns ENOENT, it logs a warning and continues instead of retrying or treating the output set as incomplete.
- Later, any files that were successfully read are unlinked during post-processing.
That means if history is ahead of the actual filesystem by even a few milliseconds, the wrapper can return partial or empty outputs for an otherwise successful prompt.
Relevant source paths in v1.17.1:
src/comfy.ts (runPromptAndGetOutputs, getPromptOutputs)
src/server.ts (postProcessOutputs unlink step)
Expected behavior
If /history/{promptId} says the prompt is completed but one or more history-listed files are temporarily unreadable with ENOENT, the wrapper should keep polling for a short grace period instead of treating the output set as final.
Actual behavior
The wrapper logs Failed to read file ... ENOENT, does not retry those files, and can continue with partial outputs.
Notes
I cannot fully rule out a custom node producing optional outputs or reporting files slightly before they are durable on disk.
However, even in that case, the current wrapper behavior makes the problem much worse because ENOENT is treated as a soft warning with no delayed re-check.
Suggested fix
A robust fix would be one of these:
- In
getPromptOutputs(), if any history-listed file returns ENOENT, treat the output set as "not ready yet" for a short bounded retry window.
- Or make the history poller continue until all history-listed files are readable, or a timeout is reached.
- Optionally distinguish between:
ENOENT for maybe-late files: retry
- missing optional outputs: eventually give up after timeout and log clearly
At minimum, swallowing ENOENT and immediately returning the partial output set seems unsafe.
Environment
comfyui-api: v1.17.1
- observed on Dockerized worker setup with
/output mounted from host storage
If helpful, I can also provide a small patch proposal for src/comfy.ts that keeps polling when history-listed files are still missing.
Summary
On
v1.17.1, we are seeing intermittent cases where a prompt reachesexecution_success/completed, butcomfyui-apiimmediately tries to read files listed in/history/{prompt_id}and some of them are not readable yet.This produces warnings like:
Retrying the same request often succeeds.
Why this looks like a wrapper race condition
After reading the source for
v1.17.1, the sequence seems to be:runPromptAndGetOutputs()waits for either websocket completion or history polling.execution_successwins, it logsPrompt <id> completed, then speeds up history polling to30ms.getPromptOutputs()fetches/history/{promptId}.status.completed === true, it iterates every history-listed output file and immediately doesreadFile(outputDir/filename).readFile()returnsENOENT, it logs a warning and continues instead of retrying or treating the output set as incomplete.That means if history is ahead of the actual filesystem by even a few milliseconds, the wrapper can return partial or empty outputs for an otherwise successful prompt.
Relevant source paths in
v1.17.1:src/comfy.ts(runPromptAndGetOutputs,getPromptOutputs)src/server.ts(postProcessOutputsunlink step)Expected behavior
If
/history/{promptId}says the prompt is completed but one or more history-listed files are temporarily unreadable withENOENT, the wrapper should keep polling for a short grace period instead of treating the output set as final.Actual behavior
The wrapper logs
Failed to read file ... ENOENT, does not retry those files, and can continue with partial outputs.Notes
I cannot fully rule out a custom node producing optional outputs or reporting files slightly before they are durable on disk.
However, even in that case, the current wrapper behavior makes the problem much worse because
ENOENTis treated as a soft warning with no delayed re-check.Suggested fix
A robust fix would be one of these:
getPromptOutputs(), if any history-listed file returnsENOENT, treat the output set as "not ready yet" for a short bounded retry window.ENOENTfor maybe-late files: retryAt minimum, swallowing
ENOENTand immediately returning the partial output set seems unsafe.Environment
comfyui-api:v1.17.1/outputmounted from host storageIf helpful, I can also provide a small patch proposal for
src/comfy.tsthat keeps polling when history-listed files are still missing.