zylon-ai/private-gpt · critical · ValueError
Visibility timeout should be greater than hard time limit
Error message
Visibility timeout should be greater than hard time limit
What it means
Config-validation ValueError from CelerySettings.validate_config: when hard_time_limit and visibility_timeout are both set, visibility_timeout must be >= hard_time_limit. Even a task that runs all the way to its hard kill must stay inside the Redis visibility window, otherwise Redis redelivers it while the first execution is still being killed, causing duplicate side effects.
Source
Thrown at private_gpt/settings/settings.py:1186
if self.hard_time_limit and self.soft_time_limit > self.hard_time_limit:
raise ValueError(
"Soft time limit should be less than or equal to hard time limit"
)
if (
self.visibility_timeout
and self.visibility_timeout < self.soft_time_limit
):
raise ValueError(
"Visibility timeout should be greater than soft time limit"
)
if self.hard_time_limit:
if (
self.visibility_timeout
and self.visibility_timeout < self.hard_time_limit
):
raise ValueError(
"Visibility timeout should be greater than hard time limit"
)
return True
class RedisSettings(BaseModel):
host: str = Field(description="Redis host")
username: str | None = Field(default=None, description="Redis username")
password: str | None = Field(default=None, description="Redis password")
database: str | None = Field(default=None, description="Redis name")
@property
def url(self) -> str:
"""Database URL without the protocol."""
username_path = f"{self.username}" if self.username else ""
password_path = f"{self.password}" if self.password else ""
credentials = (View on GitHub (pinned to 4a030776a3)
Solutions
- Set visibility_timeout above hard_time_limit (rule of thumb: hard limit plus several minutes of headroom).
- Or reduce hard_time_limit if such long tasks are a misconfiguration.
- Keep the full ordering consistent: visibility_timeout >= hard_time_limit >= soft_time_limit.
- Restart the API and all workers so the new window takes effect.
Example fix
# before celery: broker_mode: redis visibility_timeout: 300 hard_time_limit: 600 # after celery: broker_mode: redis visibility_timeout: 900 hard_time_limit: 600
Defensive patterns
Strategy: validation
Validate before calling
hard, vis = cfg['celery'].get('hard_time_limit'), cfg['celery'].get('visibility_timeout')
if hard and vis:
assert vis >= hard, f'visibility_timeout ({vis}) must be >= hard_time_limit ({hard})' Type guard
const visibilityCoversHard = (c: { visibility_timeout?: number; hard_time_limit?: number }): boolean =>
c.visibility_timeout == null || c.hard_time_limit == null || c.visibility_timeout >= c.hard_time_limit; Prevention
- Enforce ordering vis >= hard >= soft in a shared config-lint rule.
- Document the invariant next to the celery settings in your repo.
- Fail CI on settings that do not load cleanly.
When it happens
Trigger: Redis broker with visibility_timeout: 120 and hard_time_limit: 600; introducing generous hard limits (e.g. for batch jobs) on a config whose visibility_timeout was tuned for quick tasks; visibility_timeout left at a low default from a template.
Common situations: Workload mix shifting from short to long tasks; ops adding hard_time_limit for safety without revisiting broker settings; staging/prod env var divergence.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Visibility timeout should be greater than soft time limit
- Visibility timeout should be set when broker or backend is R
- Soft time limit should be less than or equal to hard time li
- Invalid system item in list: {item}
- Unsupported scheduler.tools.mode={self.scheduler.tools.mode!
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/fb54ccc2811cf25a.
Report an issue: GitHub.