immich-app/immich · error · HTTPException

Invalid request format.

Error message

Invalid request format.

What it means

Raised as FastAPI HTTPException(422) by get_entries in machine-learning/immich_ml/main.py when parsing the 'entries' form field into a PipelineRequest fails. It catches orjson.JSONDecodeError, pydantic ValidationError, KeyError, and AttributeError — i.e. malformed JSON, missing modelName, or wrong request structure — and converts them into a uniform 422.

Source

Thrown at machine-learning/immich_ml/main.py:150

def get_entries(entries: str = Form()) -> InferenceEntries:
    try:
        request: PipelineRequest = orjson.loads(entries)
        without_deps: list[InferenceEntry] = []
        with_deps: list[InferenceEntry] = []
        for task, types in request.items():
            for type, entry in types.items():
                parsed: InferenceEntry = {
                    "name": entry["modelName"],
                    "task": task,
                    "type": type,
                    "options": entry.get("options", {}),
                }
                dep = get_model_deps(parsed["name"], type, task)
                (with_deps if dep else without_deps).append(parsed)
        return without_deps, with_deps
    except (orjson.JSONDecodeError, ValidationError, KeyError, AttributeError) as e:
        log.error(f"Invalid request format: {e}")
        raise HTTPException(422, "Invalid request format.")


app = FastAPI(lifespan=lifespan)


@app.get("/")
async def root() -> ORJSONResponse:
    return ORJSONResponse({"message": "Immich ML"})


@app.get("/ping")
def ping() -> PlainTextResponse:
    return PlainTextResponse("pong")


@app.post("/predict", dependencies=[Depends(update_state)])
async def predict(
    entries: InferenceEntries = Depends(get_entries),

View on GitHub (pinned to 199723261c)

Solutions

  1. Ensure the Immich server and machine-learning container are on the same release version.
  2. Validate the entries JSON shape: top-level object keyed by task, each value keyed by type, each entry containing 'modelName'.
  3. If calling manually, build entries with orjson/json.dumps from a typed dict rather than hand-written JSON.

Example fix

# before
curl -F 'entries={"visual": {"search": {}}}' ...   # missing modelName

# after
entries = {"visual": {"search": {"modelName": "ViT-B-32__openai"}}}
curl -F 'entries=<echo $entries' ...
Defensive patterns

Strategy: validation

Validate before calling

import orjson, jsonschema
raw = orjson.loads(entries_text)
# check the {task: {type: {modelName}}} structure
for task, types in raw.items():
    for type_, entry in types.items():
        assert 'modelName' in entry, f'missing modelName for {task}/{type_}'

Type guard

def is_pipeline_request(v) -> bool:
    if not isinstance(v, dict): return False
    for types in v.values():
        if not isinstance(types, dict): return False
        for entry in types.values():
            if not isinstance(entry, dict) or 'modelName' not in entry: return False
    return True

Try / catch

try:
    entries = json.loads(raw)
except (json.JSONDecodeError, KeyError) as e:
    raise HTTPException(422, 'Invalid request format.')

Prevention

When it happens

Trigger: POST /predict with an 'entries' field that is not valid JSON, is missing the required 'modelName' key inside a type entry, or has a structure that does not match the {task: {type: {modelName, options}}} shape.

Common situations: Immich server and ML service version mismatch producing a different pipeline schema; a custom/old client sending the previous request format; truncated request body; manual curl with a malformed --form string.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/764e47cf5db7dd48. Report an issue: GitHub.