Comfy-Org/ComfyUI · error · ValueError

job id must be a string, got {type(value).__name__}

Error message

job id must be a string, got {type(value).__name__}

What it means

Raised by the job-id validator in comfy_execution/jobs.py when a client-supplied prompt/job id is not a Python str — e.g. an int or None posted via the /prompt API. The engine stores and compares job ids verbatim (history keys, websocket events, /interrupt matching), so it validates shape up front: first a type check (this error), then canonical UUID formatting. Rejecting loudly prevents silent id rewriting that would break every later exact-match lookup.

Source

Thrown at comfy_execution/jobs.py:47

    CANCELLED = 'cancelled'

    ALL = [PENDING, IN_PROGRESS, COMPLETED, FAILED, CANCELLED]


def validate_job_id(value) -> str:
    """Validate a client-supplied job (prompt) id.

    Job ids must be UUIDs in the canonical lowercase hyphenated form. The id
    is stored and compared verbatim everywhere downstream — history keys,
    websocket events, and /interrupt matching — so accepting another spelling
    would silently rewrite the client's id and then miss every exact-match
    lookup. Rejecting loudly beats that.

    Returns the id unchanged. Raises ValueError when the value is not a
    string in canonical UUID form.
    """
    if not isinstance(value, str):
        raise ValueError(f"job id must be a string, got {type(value).__name__}")
    if str(uuid.UUID(value)) != value:
        raise ValueError("job id must be a UUID in canonical lowercase hyphenated form")
    return value


# Media types that can be previewed in the frontend
PREVIEWABLE_MEDIA_TYPES = frozenset({'images', 'video', 'audio', '3d', 'text'})

# 3D file extensions for preview fallback (no dedicated media_type exists)
THREE_D_EXTENSIONS = frozenset({'.obj', '.fbx', '.gltf', '.glb', '.usdz'})

# Text file extensions for preview fallback (the formats SaveText can produce)
TEXT_EXTENSIONS = frozenset({'.txt', '.md', '.json'})


def has_3d_extension(filename: str) -> bool:
    lower = filename.lower()
    return any(lower.endswith(ext) for ext in THREE_D_EXTENSIONS)

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Send the id as a string in canonical lowercase hyphenated UUID form: str(uuid.uuid4()) in the client.
  2. If using numeric ids internally, map them to a UUID string for the API call and keep the mapping client-side.
  3. Check the JSON payload with a print/inspect before posting — ensure no int/None sneaks into the id field.
  4. Regenerate the id each queue request rather than reusing stale objects of the wrong type.

Example fix

# before
client.queue_prompt(workflow, prompt_id=12345)  # int -> ValueError

# after
import uuid
client.queue_prompt(workflow, prompt_id=str(uuid.uuid4()))
Defensive patterns

Strategy: type-guard

Validate before calling

assert isinstance(prompt_id, str), f'prompt_id must be str, got {type(prompt_id).__name__}'

Type guard

def is_valid_job_id(v) -> bool:
    if not isinstance(v, str): return False
    try: return str(uuid.UUID(v)) == v
    except ValueError: return False

Prevention

When it happens

Trigger: POSTing to /prompt with client_id/prompt_id as a JSON number (e.g. 12345) or omitting it such that a non-string default reaches the validator; any custom client passing an integer id where the API contract expects the string form of a UUID.

Common situations: Script/API clients that generate ids with random.getrandbits or use numeric primary keys and pass them unstringified; JSON serializers configured to coerce UUIDs to something other than strings; older custom frontends unaware of the UUID requirement.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/d31f4bcbd24d5862. Report an issue: GitHub.