{"record":{"id":"8b0f809a38d429af","repo":"dgraph-io/dgraph","slug":"too-many-pending-tasks-please-try-again-later","errorCode":null,"errorMessage":"too many pending tasks, please try again later","messagePattern":"too many pending tasks, please try again later","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"worker/queue.go","lineNumber":189,"sourceCode":"\tdefault:\n\t\tpanic(fmt.Sprintf(\"invalid TaskKind: %d\", kind))\n\t}\n\n\tt.logMu.Lock()\n\tdefer t.logMu.Unlock()\n\n\ttask := taskRequest{\n\t\tid:  t.newId(),\n\t\treq: req,\n\t}\n\tselect {\n\t// t.logMu must be acquired before pushing to t.queue, otherwise the worker might start the\n\t// task, and won't be able to find it in t.log.\n\tcase t.queue <- task:\n\t\tt.log.Set(task.id, newTaskMeta(kind, TaskStatusQueued).uint64())\n\t\treturn task.id, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"too many pending tasks, please try again later\")\n\t}\n}\n\n// get retrieves metadata for a given task ID.\nfunc (t *tasks) get(id uint64) (TaskMeta, error) {\n\tif t == nil {\n\t\treturn 0, fmt.Errorf(\"task queue hasn't been initialized yet\")\n\t}\n\n\tif id == 0 || id == math.MaxUint64 {\n\t\treturn 0, fmt.Errorf(\"task ID is invalid: %d\", id)\n\t}\n\tt.logMu.Lock()\n\tdefer t.logMu.Unlock()\n\tmeta := TaskMeta(t.log.Get(id))\n\tif meta == 0 {\n\t\treturn 0, fmt.Errorf(\"task does not exist or has expired\")\n\t}","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/worker/queue.go#L171-L207","documentation":"enqueue pushes new tasks onto a bounded buffered channel t.queue; when the channel is full, the select falls to the default branch and rejects the task with 'too many pending tasks, please try again later'. The queue runs one task at a time, so a burst of submissions or a stuck task fills the buffer.","triggerScenarios":"Calling Enqueue when t.queue already holds its maximum number of pending tasks — many queued backups/exports while the single worker is blocked on a long-running task.","commonSituations":"Automated backup schedules piling up because one backup is hung on slow storage; multiple clients submitting exports concurrently; the worker stuck on an I/O-bound task causing backlog growth.","solutions":["Retry with exponential backoff — the error explicitly advises trying later","Serialize task submissions client-side or add a distributed lock/queue in front of the cluster","Investigate why the running task is slow/hung (long backup, storage latency) and cancel/fix it","Reduce frequency of scheduled backups/exports or cluster-shard the workload"],"exampleFix":"// before\nid, err := tasks.Enqueue(req)\nif err != nil { return err }\n// after\nvar id uint64\nvar err error\nfor attempt := 0; attempt < 5; attempt++ {\n    id, err = tasks.Enqueue(req)\n    if err == nil || !strings.Contains(err.Error(), \"too many pending tasks\") { break }\n    time.Sleep(time.Duration(1<<attempt) * time.Second)\n}","handlingStrategy":"retry","validationCode":"// Check current backlog before submitting (if exposed)\n// or simply rate-limit client-side:\nif inflight >= maxInflight { return fmt.Errorf(\"local submission limit reached\") }","typeGuard":null,"tryCatchPattern":"var id uint64\nvar err error\nfor i := 0; i < 5; i++ {\n    id, err = tasks.Enqueue(req)\n    if err == nil || !strings.Contains(err.Error(), \"too many pending tasks\") { break }\n    time.Sleep(time.Duration(1<<i) * time.Second)\n}","preventionTips":["Throttle and serialize task submissions client-side","Monitor for long-running tasks backing up the single-worker queue","Alert on repeated 'too many pending tasks' occurrences","Schedule backups/exports to avoid overlap"],"tags":["backpressure","rate-limit","task-queue","dgraph"],"backgroundTag":"queue-full","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}