{"record":{"id":"479a683bae435625","repo":"temporalio/temporal","slug":"elasticsearch-processor-is-nil","errorCode":null,"errorMessage":"Elasticsearch processor is nil","messagePattern":"Elasticsearch processor is nil","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"common/persistence/visibility/store/elasticsearch/visibility_store.go","lineNumber":372,"sourceCode":"\t\t}\n\t\t// Returns non-retryable Internal error here because these errors are unexpected.\n\t\t// Visibility task processor retries all errors though; therefore, new request will be generated for the same visibility task.\n\t\treturn serviceerror.NewInternalf(\"visibility task received error: %v\", err)\n\t}\n\n\tif !ack {\n\t\t// Returns retryable Unavailable error here because NACK from bulk processor\n\t\t// means that this request wasn't processed successfully and needs to be retried.\n\t\t// Visibility task processor retries all errors anyway, therefore, new request will be generated for the same visibility task.\n\t\treturn serviceerror.NewUnavailable(\"visibility task received NACK\")\n\t}\n\treturn nil\n}\n\nfunc (s *VisibilityStore) checkProcessor() {\n\tif s.processor == nil {\n\t\t// must be a bug, check history setup\n\t\tpanic(\"Elasticsearch processor is nil\")\n\t}\n\tif s.processorAckTimeout == nil {\n\t\t// must be a bug, check history setup\n\t\tpanic(\"config.ESProcessorAckTimeout is nil\")\n\t}\n}\n\nfunc (s *VisibilityStore) ListWorkflowExecutions(\n\tctx context.Context,\n\trequest *manager.ListWorkflowExecutionsRequestV2,\n) (*store.InternalListExecutionsResponse, error) {\n\tp, err := s.BuildSearchParametersV2(request, s.GetListFieldSorter)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsearchResult, err := s.esClient.Search(ctx, p)\n\tif err != nil {","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/visibility/store/elasticsearch/visibility_store.go#L354-L390","documentation":"VisibilityStore.checkProcessor panics when the Elasticsearch visibility store's background indexer (processor) is nil. The processor is the async bulk-indexing pipeline created during store initialization (wired up by history service config); AddBulkRequestAndWait calls checkProcessor before use, and a nil processor means the store was constructed without the required ES indexing machinery — commented in source as 'must be a bug, check history setup'.","triggerScenarios":"Calling AddBulkRequestAndWait (directly or via visibility manager write paths) on a VisibilityStore created with a nil processor — e.g. the store was built for a non-ES backend but registered as ES, or the NewVisibilityStore wiring skipped processor creation while config still selected Elasticsearch.","commonSituations":"Config choosing elasticsearch visibility store but initialization code path failing silently to create the processor; double store instantiation where the processor is attached to a different instance; tests constructing VisibilityStore struct literals without processor; startup ordering bugs in history service setup.","solutions":["Verify visibility persistence config: ensure the store is truly Elasticsearch and that history service setup creates the processor (esVisibilityStore init in history service bootstrap).","Use the standard NewVisibilityStore constructor path so processor and processorAckTimeout are always populated; never build the struct literal directly in tests.","If running non-ES (SQL/Cassandra) visibility, fix the store selection so ES-specific code paths are not invoked.","Check startup logs/config for earlier processor-creation errors and restart the service after fixing wiring."],"exampleFix":"// before (test/store construction)\nstore := &elasticsearch.VisibilityStore{ESClient: client, Logger: logger} // processor nil\n// after\nstore := elasticsearch.NewVisibilityStore(client, schema, \"index\", logger, metricClient, esCfg, esProcessorCfg) // processor created internally","handlingStrategy":"validation","validationCode":"func (s *VisibilityStore) bulkReady() error {\n    if s.processor == nil { return errors.New(\"ES processor not initialized; check history setup\") }\n    if s.processorAckTimeout == nil { return errors.New(\"ESProcessorAckTimeout not configured\") }\n    return nil\n}","typeGuard":"func (s *VisibilityStore) processorReady() bool { return s.processor != nil && s.processorAckTimeout != nil }","tryCatchPattern":"// panics here are process-fatal; check readiness before bulk writes\nif err := store.BulkReady(); err != nil { logger.Error(err.Error()); return err }\nreturn store.AddBulkRequestAndWait(ctx, req)","preventionTips":["Always construct VisibilityStore via its constructor, never struct literals","Assert processor initialization during service bootstrap/health checks","Align visibility store kind with actual backend config (ES vs SQL)"],"tags":["elasticsearch","panic","visibility","initialization"],"backgroundTag":"es-processor-not-initialized","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}