Tom Han
02/17/2026, 6:30 PMPANIC: unprotected error in call to Lua API (table overflow)? Seems like a redis issue but I am not sure where to look at. @MarvinMarvin
02/17/2026, 6:30 PMMarvin
02/17/2026, 6:35 PMSMEMBERS and returns them in a Lua table. If a single “leader” accumulates thousands of followers, the script can blow up.
- Concurrency lease storage (Redis): a create/revoke script loops over a variable number of keys and does `HSET`s/index cleanup. If a single lease references a very large number of limits, the Lua table can grow too large.
First, confirm whether Prefect is actually using Redis
Run this to see effective settings:
prefect config view | grep -i 'redis\|events\|concurrency\|docket'
If you see any of these pointing at Redis, Prefect is using it:
- PREFECT_SERVER_EVENTS_MESSAGING_BROKER / PREFECT_SERVER_EVENTS_MESSAGING_CACHE / PREFECT_SERVER_EVENTS_CAUSAL_ORDERING
- PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE
- PREFECT_SERVER_DOCKET_URL
Quick isolation steps
- If events are on Redis, switch them to memory temporarily and restart the server:
- Unset or set these back to memory implementations:
- PREFECT_SERVER_EVENTS_MESSAGING_BROKER=prefect.server.utilities.messaging.memory
- PREFECT_SERVER_EVENTS_MESSAGING_CACHE=prefect.server.utilities.messaging.memory
- PREFECT_SERVER_EVENTS_CAUSAL_ORDERING=prefect.server.events.ordering.memory
- If concurrency lease storage is on Redis, switch back to memory to test:
- PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE=prefect.server.concurrency.lease_storage.memory
- If Docket points at Redis, set:
- PREFECT_SERVER_DOCKET_URL=memory://
If the panic disappears after any of the above, we’ve found the culprit.
What to check in Redis
- See which keys are growing large:
redis-cli --scan --pattern 'prefect*followers*' | head
redis-cli --scan --pattern 'prefect*concurrency*' | head
# For any suspicious key:
redis-cli MEMORY USAGE <key>
redis-cli SCARD <key> # for sets
redis-cli ZCARD <key> # for sorted sets
- Capture the failing script/key names:
redis-cli monitor | grep -i eval
That will show the EVAL/EVALSHA calls and keys being touched around the time of the panic.
Mitigations if events/ordering is the source
- Ensure you’re not accidentally fanning thousands of “followers” onto a single event. This can happen if many flows subscribe to the same trigger pattern without deduplication.
- Trim/rotate old event state; the Redis messaging/ordering layer already trims, but if you find a single “followers” key with huge cardinality, you can safely delete it while the server is stopped to recover:
# Only after stopping Prefect server
redis-cli DEL <the-large-followers-key>
- If you don’t need cross-process causal ordering, keep events on memory to avoid Redis entirely.
Mitigations if concurrency leases are the source
- Reduce the number of concurrency limits a single run acquires at once; avoid patterns where a lease covers a large number of “resource_ids”.
- If you accidentally created many limits/holders, you can clear stale lease state (while the server is stopped) by deleting obviously stale keys under your concurrency prefix.
General hardening
- Upgrade to the latest Prefect 3.x and prefect-redis packages (bug fixes land there first).Marvin
02/17/2026, 6:35 PMlua-time-limit (default is usually fine; your issue is overflow, not timeout)
- maxmemory and an eviction policy appropriate for your workload
- If you’re also hitting Postgres timeouts, that’s usually separate (pool exhaustion or long-running queries). If you can share the exact Postgres error and timing, I can recommend DB-side tuning next.
Can you share:
- Which of the Redis-backed features above you’ve enabled
- Redis version and memory settings
- Rough scale (events per second, number of deployments subscribing to events, number of concurrency limits)
- A short snippet of the Redis MONITOR output around the panic (redacting secrets)
References
- Prefect Redis integration (source): prefect-redis repo
- Lease storage implementation: lease_storage.py
- Events causal ordering: ordering.py
- Messaging: messaging.py
- Prefect settings overview: Settings docs
- Redis Lua scripting background: Redis Lua scriptingNate
02/17/2026, 6:48 PMMarvin
02/17/2026, 6:48 PMTom Han
02/17/2026, 6:50 PMPostgreSQL is the root cause, Redis is the victim.
1. Postgres gets slow. The RecentDeploymentsScheduler was already struggling from day 1 (5s+ on a 5s loop), and it got progressively worse over the 14 days —
up to 37 seconds. On top of that, there's a connection from 10.7.30.110 that's been idle in transaction since Feb 9, holding a connection slot and
potentially locks.
2. docket tasks pile up in Redis. Every time a worker polls for work, Prefect schedules mark_work_queues_ready and mark_deployments_ready tasks into Redis
via docket. These tasks need to write to Postgres — but Postgres is too slow/unresponsive. You can see them timing out at 29 seconds each:
17:22:56.275 | ERROR | docket.worker - ↫ [ 29390ms] mark_work_queues_ready(...)
17:22:56.282 | ERROR | docket.worker - ↫ [ 29385ms] mark_work_queues_ready(...)
17:22:56.285 | ERROR | docket.worker - ↫ [ 29391ms] mark_deployments_ready(...)
3. Workers keep polling, docket keeps queuing. Two workers polling every few seconds = a constant stream of new docket tasks being added to Redis. But the
old ones can't complete because Postgres is choked. So Redis accumulates a growing backlog of pending/failed tasks.
4. Redis overflows. After enough accumulation → PANIC: unprotected error in call to Lua API (table overflow).Nate
02/17/2026, 6:52 PMTom Han
02/17/2026, 6:53 PMMarvin
02/17/2026, 6:54 PMPREFECT_SERVER_EVENTS_MESSAGING_BROKER
- PREFECT_SERVER_EVENTS_MESSAGING_CACHE
- PREFECT_SERVER_EVENTS_CAUSAL_ORDERING
- Source: server/events settings
- Concurrency leases (memory by default):
- PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE
- Source: server/concurrency settings
- Docket (in-process memory by default):
- PREFECT_SERVER_DOCKET_URL
- Source: server/docket settings
- General settings doc: Prefect settings
About the Redis Lua “table overflow” panic
- Prefect’s Redis paths do use small Lua scripts (in those files above) for atomic updates. A “table overflow” can happen if those scripts operate on very large collections (e.g., a set with thousands of members returned by SMEMBERS), or if you attach an unusually large number of resources/limits to a single lease.
- If you haven’t enabled the Redis-backed features above, Prefect won’t be calling Redis at all—so the panic would be from some other component using your Redis.
Quick triage checklist
1) Confirm if Prefect is using Redis at all
prefect config view | grep -i 'redis\|events\|concurrency\|docket'
If any of the three events settings, the concurrency lease storage, or the docket URL point to Redis, Prefect is using it.
2) If using Redis, see what’s blowing up
- Temporarily switch Redis-backed features to memory and restart Prefect to isolate:
# events back to memory
export PREFECT_SERVER_EVENTS_MESSAGING_BROKER=prefect.server.utilities.messaging.memory
export PREFECT_SERVER_EVENTS_MESSAGING_CACHE=prefect.server.utilities.messaging.memory
export PREFECT_SERVER_EVENTS_CAUSAL_ORDERING=prefect.server.events.ordering.memory
# concurrency leases back to memory
export PREFECT_SERVER_CONCURRENCY_LEASE_STORAGE=prefect.server.concurrency.lease_storage.memory
# docket back to in-process
export PREFECT_SERVER_DOCKET_URL=memory://
If the panic stops, we’ve confirmed Prefect’s Redis path is involved.
3) Inspect Redis around the crash
- Identify big keys and script activity:
redis-cli SLOWLOG get 20
redis-cli monitor | grep -iE 'EVAL|EVALSHA' # run briefly; very noisy
redis-cli --scan --pattern 'prefect*' | head
# For suspects:
redis-cli TYPE <key>
redis-cli SCARD <key> # sets
redis-cli ZCARD <key> # sorted sets
redis-cli HLEN <key> # hashes
redis-cli MEMORY USAGE <key>
If you find a massive “followers” set (events ordering) or a giant hash/index (concurrency), that’s a likely root cause.
Mitigations if it’s Prefect’s Redis usage
- Events/ordering:Marvin
02/17/2026, 6:54 PMmaxmemory and eviction policy.
- Keep lua-time-limit default unless you see timeouts (your error is overflow, not time).
On your Postgres timeouts
Since you also mentioned DB timeouts, double-check pool sizing vs. your server concurrency. Relevant settings:
- Pool sizing/timeouts: server/database settings
- PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_SIZE (default 5)
- PREFECT_SERVER_DATABASE_SQLALCHEMY_MAX_OVERFLOW (default 10)
- PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_TIMEOUT (default 30s)
- PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_RECYCLE (default 3600s)
- PREFECT_SERVER_DATABASE_TIMEOUT (statement timeout, default ~10s)
- Engine creation ref: engine configuration
- If you run multiple API workers, scale pool_size accordingly or front with PgBouncer (and set statement_cache_size=0 in connect_args for transaction pooling).
Can you share:
- Which Prefect Redis settings (if any) are enabled in your env
- Redis version and whether other services share that Redis
- A snippet of Redis SLOWLOG or brief MONITOR around the panic
- An example Postgres timeout message (from server logs)
I’ll use that to pinpoint whether the crash is from Prefect’s Redis paths and recommend precise fixes.Nate
02/17/2026, 6:56 PMTom Han
02/17/2026, 7:08 PMNate
02/17/2026, 7:10 PMprefect.flow-run.* syntax for the service to say "clean up these ones" and when to clean them upTom Han
02/17/2026, 7:16 PMNate
02/17/2026, 7:20 PMNate
02/17/2026, 7:21 PMEventPersister etc that is configured via env vars, gets a db connection directly and starts via prefect server services startTom Han
02/17/2026, 9:43 PMNate
02/17/2026, 9:45 PMTom Han
02/17/2026, 9:45 PMTom Han
02/17/2026, 9:46 PMNate
02/17/2026, 9:46 PMNate
02/17/2026, 9:48 PMalso as a side question, it would be nice to check all prefect related service health in one place (DB, actual server, redis, worker health) in a dashboard, is that something that could be done easily?another interesting point, today no. but you could imagine heartbeat-style events emitted from background services, enabling a "background service health" dashboard in the new oss ui
Tom Han
02/17/2026, 9:50 PMTom Han
02/17/2026, 9:51 PMNate
02/17/2026, 9:52 PMTom Han
02/17/2026, 9:54 PMBring your towel and join one of the fastest growing data communities. Welcome to our second-generation open source orchestration platform, a completely rethought approach to dataflow automation.
Powered by