invoke-ai/InvokeAI · warning · HTTPException

str(e)

Error message

str(e)

What it means

This is a 422 Unprocessable Entity raised by the PATCH/PUT runtime-config endpoint when the requested generation devices (e.g. torch device strings like 'cuda:99') cannot be resolved by TorchDevice.get_generation_devices. InvokeAI pre-validates device changes with the same resolution logic as the startup path so a bad config can never be persisted and break the next startup. The detail is str(e) from the underlying ValueError, typically naming the invalid device.

Solutions

  1. Read the detail message to identify the offending device string
  2. Use a valid torch device available on this machine (e.g. 'cuda:0', 'mps', 'cpu'); verify with python -c "import torch; print(torch.cuda.device_count())"
  3. Send only the fields you intend to change (exclude_unset) instead of echoing devices copied from another machine
  4. Remove the generation_devices key from the request if you don't mean to change devices

Example fix

// before
{ "generation_devices": { "denoising": "cuda:99", "clip": "cuda:99" } }
// after
{ "generation_devices": { "denoising": "cuda:0", "clip": "cuda:0" } }
Defensive patterns

Strategy: validation

Validate before calling

import torch
from invokeai.backend.util.devices import TorchDevice

def validate_generation_devices(devices: dict) -> None:
    # mirror the server's pre-check before sending the config
    TorchDevice.get_generation_devices(devices)  # raises ValueError if invalid

Type guard

def is_valid_device(name: str) -> bool:
    import torch
    if name == 'auto':
        return True
    base = name.split(':')[0]
    if base == 'cuda':
        idx = int(name.split(':')[1]) if ':' in name else 0
        return torch.cuda.is_available() and idx < torch.cuda.device_count()
    return base in ('mps', 'cpu')

Try / catch

try:
    resp = requests.patch(f'{base}/app/config', json=payload)
    resp.raise_for_status()
except requests.HTTPError as e:
    if e.response.status_code == 422:
        print('Invalid device:', e.response.json()['detail'])

Prevention

When it happens

Trigger: PATCHing runtime config with generation_devices containing an invalid/unavailable torch device string (typo, nonexistent CUDA index like 'cuda:99' on a 2-GPU box, CPU-only machine given 'cuda:0').

Common situations: Copying config from a multi-GPU machine to a smaller box; typo in device name ('cuda' vs 'cuda:0' vs 'gpu'); Docker container without GPU passthrough; driver/CUDA mismatch making a device invisible to torch.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/17ff695dbfc01021. Report an issue: GitHub.

Appendix: source

Thrown at invokeai/app/api/routers/app_info.py:271

@app_router.patch(
    "/runtime_config",
    operation_id="update_runtime_config",
    status_code=200,
    response_model=InvokeAIAppConfigWithSetFields,
)
def update_runtime_config(
    _: AdminUserOrDefault,
    changes: UpdateAppGenerationSettingsRequest = Body(description="Writable runtime configuration changes"),
) -> InvokeAIAppConfigWithSetFields:
    # The request model validates the *shape* of generation_devices; also verify the devices exist
    # on this machine before persisting, so we can't write a config that fails on the next startup
    # (e.g. 'cuda:99' on a 2-GPU box). Same resolution the startup path uses.
    if changes.generation_devices is not None:
        try:
            TorchDevice.get_generation_devices(changes.generation_devices)
        except ValueError as e:
            raise HTTPException(status_code=422, detail=str(e))
    with _EXTERNAL_PROVIDER_CONFIG_LOCK:
        config = get_config()
        update_dict = changes.model_dump(exclude_unset=True)
        config.update_config(update_dict)

        if config.config_file_path.exists():
            persisted_config = load_and_migrate_config(config.config_file_path)
        else:
            persisted_config = DefaultInvokeAIAppConfig()

        persisted_config.update_config(update_dict)
        persisted_config.write_file(config.config_file_path)
        return InvokeAIAppConfigWithSetFields(set_fields=config.model_fields_set, config=_redact_config_secrets(config))


@app_router.get(
    "/external_providers/status",
    operation_id="get_external_provider_statuses",

View on GitHub (pinned to 0b6a024f2f)