OpenBMB/ChatDev · error · HTTPException

log_level must be one of DEBUG, INFO, WARNING, ERROR…

Error message

log_level must be one of DEBUG, INFO, WARNING, ERROR, CRITICAL

What it means

run_workflow_sync converts request.log_level to the LogLevel enum; a ValueError yields HTTP 400 with the accepted list. Unlike the async/batch endpoints, this endpoint documents the full set DEBUG, INFO, WARNING, ERROR, CRITICAL.

Solutions

  1. Use one of DEBUG, INFO, WARNING, ERROR, CRITICAL exactly as cased in the LogLevel enum
  2. Omit log_level to use the server default
  3. Normalize log level strings client-side against the accepted list before sending

Example fix

# before
"log_level": "trace"
# after
"log_level": "DEBUG"
Defensive patterns

Strategy: validation

Validate before calling

LEVELS = {'DEBUG','INFO','WARNING','ERROR','CRITICAL'}
if log_level is not None:
    assert log_level in LEVELS, f'log_level must be one of {LEVELS}'

Type guard

def is_valid_level(v: str | None) -> bool:
    return v is None or v in {'DEBUG','INFO','WARNING','ERROR','CRITICAL'}

Try / catch

except HTTPError as e:
    if e.response.status_code == 400 and 'log_level' in e.response.text:
        req['log_level'] = 'INFO'; client.run(req)

Prevention

When it happens

Trigger: POST to the sync workflow endpoint with log_level values like TRACE, FINE, lowercase variants not accepted by the enum, or arbitrary strings.

Common situations: Reusing log level strings from Python logging or log4j conventions that don't map to this enum; case sensitivity mismatches.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27). Data as JSON: /api/errors/1cdc66bb1f7faf9c. Report an issue: GitHub.

Appendix: source

Thrown at server/routes/execute_sync.py:159

        "token_usage": token_usage,
        "output_dir": graph_context.directory,
    }
    return final_message, meta


def _sse_event(event_type: str, data: Any) -> str:
    payload = json.dumps(data, ensure_ascii=False, default=str)
    return f"event: {event_type}\ndata: {payload}\n\n"


@router.post("/api/workflow/run")
async def run_workflow_sync(request: WorkflowRunRequest, http_request: Request):
    try:
        resolved_log_level: Optional[LogLevel] = None
        if request.log_level:
            resolved_log_level = LogLevel(request.log_level)
    except ValueError:
        raise HTTPException(
            status_code=400,
            detail="log_level must be one of DEBUG, INFO, WARNING, ERROR, CRITICAL",
        )

    accepts_stream = _SSE_CONTENT_TYPE in (http_request.headers.get("accept") or "")
    if not accepts_stream:
        try:
            result = await run_in_threadpool(
                run_workflow,
                request.yaml_file,
                task_prompt=request.task_prompt,
                attachments=request.attachments,
                session_name=request.session_name,
                variables=request.variables,
                log_level=resolved_log_level,
            )
        except FileNotFoundError as exc:
            raise HTTPException(status_code=404, detail=str(exc))

View on GitHub (pinned to 4fb2db0ea9)