Skip to content

Prompt can complete before all history-listed output files are readable, causing intermittent ENOENT and partial/missing outputs #156

@Pililink

Description

@Pililink

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:

  1. runPromptAndGetOutputs() waits for either websocket completion or history polling.
  2. If websocket execution_success wins, it logs Prompt <id> completed, then speeds up history polling to 30ms.
  3. getPromptOutputs() fetches /history/{promptId}.
  4. If status.completed === true, it iterates every history-listed output file and immediately does readFile(outputDir/filename).
  5. If readFile() returns ENOENT, it logs a warning and continues instead of retrying or treating the output set as incomplete.
  6. 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:

  1. In getPromptOutputs(), if any history-listed file returns ENOENT, treat the output set as "not ready yet" for a short bounded retry window.
  2. Or make the history poller continue until all history-listed files are readable, or a timeout is reached.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions