apache/druid · error · IllegalStateException
A realtime appenderator was already created for this peon's…
Error message
A realtime appenderator was already created for this peon's task.
What it means
PeonAppenderatorsManager manages at most one appenderator per peon (task worker process). createRealtimeAppenderatorForTask throws this IllegalStateException if a realtime appenderator already exists, because the manager only supports a single realtime appenderator for the lifetime of the peon.
Solutions
- Ensure createRealtimeAppenderatorForTask is called at most once per peon; guard with an initialized flag in task code
- Call the manager's shutdown/cleanup path before attempting to recreate the appenderator
- Check task logs for an earlier creation call and fix duplicate initialization in task lifecycle code
Example fix
// before
appenderatorManager.createRealtimeAppenderatorForTask(...) // called on both init and retry
// after
if (!initialized) {
appenderator = appenderatorManager.createRealtimeAppenderatorForTask(...);
initialized = true;
} Defensive patterns
Strategy: validation
Validate before calling
if (peonManager.realtimeAppenderatorExists()) throw new IllegalStateException("appenderator already created"); Type guard
boolean canCreateRealtime = manager != null && !manager.hasRealtimeAppenderator();
Try / catch
try { manager.createRealtimeAppenderatorForTask(...); } catch (ISE e) { log.warn("already created; reusing existing appenderator"); } Prevention
- Create the appenderator exactly once in task lifecycle init
- Guard creation with an idempotent initialized flag
- Never recreate appenderators on retry without shutdown first
When it happens
Trigger: Calling createRealtimeAppenderatorForTask twice within the same peon process, e.g. task restart logic re-invoking appenderator creation without first calling shutdown, or custom task code re-entering initialization after a failure.
Common situations: Custom indexing task implementations that retry ingestion setup; frameworks re-invoking task initialization after transient failures; double registration of the same task in an embedded peon.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- A batch appenderator was already created for this peon's…
- Can't add [ , ] to non-empty…
- Cannot have both awaitChannels and awaitFutures
- Conflicting key[ ] calculated via keyMapper for original…
- Expected single element
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/34826bc565767b31.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/segment/realtime/appenderator/PeonAppenderatorsManager.java:93
IndexIO indexIO,
IndexMerger indexMerger,
QueryRunnerFactoryConglomerate conglomerate,
DataSegmentAnnouncer segmentAnnouncer,
ServiceEmitter emitter,
QueryProcessingPool queryProcessingPool,
JoinableFactory joinableFactory,
Cache cache,
CacheConfig cacheConfig,
CachePopulatorStats cachePopulatorStats,
PolicyEnforcer policyEnforcer,
RowIngestionMeters rowIngestionMeters,
ParseExceptionHandler parseExceptionHandler,
CentralizedDatasourceSchemaConfig centralizedDatasourceSchemaConfig,
TaskIntervalUnlocker taskIntervalUnlocker
)
{
if (realtimeAppenderator != null) {
throw new ISE("A realtime appenderator was already created for this peon's task.");
} else if (batchAppenderator != null) {
throw new ISE("A batch appenderator was already created for this peon's task.");
} else {
realtimeAppenderator = Appenderators.createRealtime(
segmentLoaderConfig,
taskId,
schema,
config,
metrics,
dataSegmentPusher,
jsonMapper,
indexIO,
indexMerger,
conglomerate,
segmentAnnouncer,
emitter,
queryProcessingPool,
cache,View on GitHub (pinned to 9b90983fd2)