zylon-ai/private-gpt · critical · ValueError

scheduler.tools.mode={self.scheduler.tools.mode!r} requires

Error message

scheduler.tools.mode={self.scheduler.tools.mode!r} requires scheduler.chat.mode='arq' so tool callbacks can resume shared chat state.

What it means

Startup-time ValueError from the root Settings model_validator: choosing scheduler.tools.mode='celery' forces scheduler.chat.mode='arq'. Celery tool workers publish their results back through shared chat state that only the ARQ/Redis chat pipeline can resume, so the combination (celery tools + local chat) is rejected at boot.

Source

Thrown at private_gpt/settings/settings.py:1878

        description="Scheduler configuration for chat and tool workers.",
    )

    @model_validator(mode="after")
    def validate_chat_scheduler_configuration(self) -> "Settings":
        if self.scheduler.chat.mode not in {"local", "arq"}:
            raise ValueError(
                f"Unsupported scheduler.chat.mode={self.scheduler.chat.mode!r}. "
                "Supported chat scheduler modes are 'local' and 'arq'."
            )

        if self.scheduler.tools.mode not in {"local", "celery"}:
            raise ValueError(
                f"Unsupported scheduler.tools.mode={self.scheduler.tools.mode!r}. "
                "Supported tool scheduler modes are 'local' and 'celery'."
            )

        if self.scheduler.tools.mode == "celery" and self.scheduler.chat.mode != "arq":
            raise ValueError(
                f"scheduler.tools.mode={self.scheduler.tools.mode!r} requires "
                "scheduler.chat.mode='arq' so tool callbacks can resume shared "
                "chat state."
            )

        if self.scheduler.chat.mode == "local":
            return self

        if self.stream.broker != "redis":
            raise ValueError(
                f"scheduler.chat.mode={self.scheduler.chat.mode!r} requires stream.broker=redis "
                "because API and chat worker processes must share stream state."
            )

        return self


"""

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Set scheduler.chat.mode: arq alongside scheduler.tools.mode: celery.
  2. Or keep tools on 'local' if you are not ready to run the ARQ chat worker.
  3. When chat mode is arq, also ensure stream.broker is redis (the sibling validator requires it).
  4. Deploy the ARQ chat worker process before switching modes, or chat requests will queue with no consumer.

Example fix

# before
scheduler:
  chat:
    mode: local
  tools:
    mode: celery
# after
scheduler:
  chat:
    mode: arq
  tools:
    mode: celery
Defensive patterns

Strategy: validation

Validate before calling

s = cfg.get('scheduler', {})
chat, tools = s.get('chat', {}).get('mode'), s.get('tools', {}).get('mode')
assert not (tools == 'celery' and chat != 'arq'), 'celery tools requires arq chat'

Type guard

const schedulerPairValid = (s: { chat: { mode: string }; tools: { mode: string } }): boolean =>
  !(s.tools.mode === 'celery' && s.chat.mode !== 'arq');

Prevention

When it happens

Trigger: settings.yaml with scheduler: {chat: {mode: local}, tools: {mode: celery}} — typically someone enables Celery for heavy tool calls but leaves chat on the default 'local'.

Common situations: Incrementally adopting distributed execution: tools first, chat later; default chat mode being local so merely adding tools.mode=celery triggers it; merged overlays where one file sets chat local and another sets tools celery.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/3b8197e0e98029ab. Report an issue: GitHub.