{"record":{"id":"3cc606833deae734","repo":"temporalio/temporal","slug":"batchsize-too-large","errorCode":null,"errorMessage":"BatchSize too large","messagePattern":"BatchSize too large","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/worker/dlq/workflow.go","lineNumber":174,"sourceCode":"\tdeleteTasksActivityName      = \"dlq-delete-tasks-activity\"\n\treadTasksActivityName        = \"dlq-read-tasks-activity\"\n\treEnqueueTasksActivityName   = \"dlq-re-enqueue-tasks-activity\"\n\n\t// deleteTasksActivityTimeout is long because all tasks are deleted in a single go. This only applies when using the\n\t// purge workflow, not when the delete activity is used in the merge workflow.\n\tdeleteTasksActivityTimeout = 5 * time.Minute * debug.TimeoutMultiplier\n\t// mergeTasksActivityTimeout controls the timeout of all activities used in the merge workflow. It is relatively\n\t// short because we're only processing a single batch of tasks at a time.\n\tmergeTasksActivityTimeout = 15 * time.Second * debug.TimeoutMultiplier\n)\n\nvar (\n\t// Module provides a [workercommon.WorkerComponent] annotated with [workercommon.WorkerComponentTag] to the graph,\n\t// given a [HistoryClient], a [TaskClientDialer], and a value for [CurrentClusterName].\n\tModule = workercommon.AnnotateWorkerComponentProvider(newComponent)\n\n\tErrNegativeBatchSize      = errors.New(\"BatchSize must be positive or 0 to use the default\")\n\tErrMergeBatchSizeTooLarge = errors.New(\"BatchSize too large\")\n\n\t// deleteActivityRetryPolicy is the retry policy for the delete activity. Currently, delete processes all messages\n\t// in one batch, so this could be expensive. As a result, we want to increase the backoff quickly to not peg the\n\t// system.\n\tdeleteActivityRetryPolicy = &temporal.RetryPolicy{\n\t\tInitialInterval:    100 * time.Millisecond,\n\t\tBackoffCoefficient: 2.0,\n\t\tMaximumAttempts:    10,\n\t}\n\t// mergeActivityRetryPolicy is the retry policy for the merge activities. Currently, merge processes one batch of\n\t// messages at a time, and each batch has a capped size determined by MaxMergeBatchSize, so this is relatively\n\t// cheap. As a result, we want to increase the backoff slowly because it's unlikely that this will hurt the system.\n\tmergeActivityRetryPolicy = &temporal.RetryPolicy{\n\t\tInitialInterval:    100 * time.Millisecond,\n\t\tBackoffCoefficient: 1.2,\n\t\tMaximumAttempts:    10,\n\t}\n)","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/worker/dlq/workflow.go#L156-L192","documentation":"ErrMergeBatchSizeTooLarge is declared in the DLQ merge workflow and returned by parseMergeParams when the user-supplied BatchSize for a DLQ merge operation exceeds the allowed maximum. Merging DLQ messages processes each batch as one unit, so an oversized batch would put excessive load on persistence; the workflow refuses to start instead.","triggerScenarios":"Calling the DLQ merge workflow (e.g. `temporal dlq merge` or MergeDLQMessages workflow) with a MergeDLQMessagesParams whose BatchSize exceeds the configured maximum batch size.","commonSituations":"Operators trying to speed up DLQ draining by setting a huge batch size; copy-pasting a default that no longer matches a lowered server-side limit after an upgrade or config change.","solutions":["Lower the BatchSize in MergeDLQMessagesParams to a value within the allowed maximum (or 0 to use the default).","Run merges without specifying BatchSize so the default is used.","Check the DLQ workflow's configured max batch size constant/config in dlq/workflow.go and align tooling with it.","Drain a large DLQ with multiple sequential merge operations instead of one oversized batch."],"exampleFix":"// before\nparams := &workerdldb.MergeDLQMessagesParams{TargetCluster: \"active\", BatchSize: 1000000}\n// after\nparams := &workerdldb.MergeDLQMessagesParams{TargetCluster: \"active\", BatchSize: 100} // within limit, or 0 for default","handlingStrategy":"validation","validationCode":"const maxMergeBatchSize = 1000 // check dlq/workflow.go for the actual limit\nif params.BatchSize > maxMergeBatchSize {\n\treturn fmt.Errorf(\"BatchSize %d exceeds max %d; use 0 for default\", params.BatchSize, maxMergeBatchSize)\n}","typeGuard":"func validMergeBatchSize(n int) bool { return n >= 0 } // 0 = default; enforce upper bound before calling","tryCatchPattern":"err := dlqWorker.MergeDLQMessages(ctx, params)\nif errors.Is(err, dlq.ErrMergeBatchSizeTooLarge) {\n\tparams.BatchSize = 0 // fall back to default size and retry\n}","preventionTips":["Use BatchSize 0 (default) unless you have measured a need for larger batches.","Keep operator tooling aligned with the configured max batch size after upgrades.","Prefer multiple sequential merge operations over one oversized batch."],"tags":["dlq","validation","go","batch-size"],"backgroundTag":"batch-size-limit-exceeded","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}