{"record":{"id":"7c34f78fb34e8b15","repo":"vectordotdev/vector","slug":"join-error-or-bad-poll","errorCode":null,"errorMessage":"join error or bad poll","messagePattern":"join error or bad poll","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/topology/builder.rs","lineNumber":1375,"sourceCode":"\n        let mut input_rx =\n            super::ready_arrays::ReadyArrays::with_capacity(input_rx, ready_array_capacity());\n\n        let mut in_flight = FuturesOrdered::new();\n        let mut shutting_down = false;\n\n        self.timer_tx.try_send_start_wait();\n        loop {\n            tokio::select! {\n                biased;\n\n                result = in_flight.next(), if !in_flight.is_empty() => {\n                    match result {\n                        Some(Ok(mut outputs_buf)) => {\n                            self.send_outputs(&mut outputs_buf).await\n                                .map_err(TaskError::wrapped)?;\n                        }\n                        _ => unreachable!(\"join error or bad poll\"),\n                    }\n                }\n\n                input_arrays = input_rx.next(), if in_flight.len() < *TRANSFORM_CONCURRENCY_LIMIT && !shutting_down => {\n                    match input_arrays {\n                        Some(input_arrays) => {\n                            let mut len = 0;\n                            for events in &input_arrays {\n                                self.on_events_received(events);\n                                len += events.len();\n                            }\n\n                            let mut t = self.transform.clone();\n                            let mut outputs_buf = self.outputs.new_buf_with_capacity(len);\n                            // Hook CPU-time accounting onto the spawned task at\n                            // the `Future::poll` boundary.\n                            // This is a separate task from the current one, so there is no double-counting.\n                            let task = spawn_timed(","sourceCodeStart":1357,"sourceCodeEnd":1393,"githubUrl":"https://github.com/vectordotdev/vector/blob/3708c39b12a93212ed8b8d7510b4cc7769cb5864/src/topology/builder.rs#L1357-L1393","documentation":"This is Vector's fanout-to-transform task in the topology builder. It pulls input batches, spawns transform futures into in_flight (bounded by the worker-thread-derived TRANSFORM_CONCURRENCY_LIMIT), and forwards outputs. The branch expects Some(Ok(outputs)); anything else - a joined future that panicked (JoinError) or a premature None - trips unreachable!('join error or bad poll'). This panic is the symptom; the root cause is an earlier panic inside a transform task.","triggerScenarios":"A spawned transform future panicking while processing events - its JoinError surfaces here - or the futures collection misbehaving (None while non-empty). Real-world event shapes reaching a transform's own panic path (unsupported event types, malformed inputs) are the usual source.","commonSituations":"A transform hitting one of its own unreachable/panic arms under real traffic (e.g. an unsupported event type or non-standard log format reaching it); high concurrency stressing task spawning; Vector bugs in fanout accounting.","solutions":["Scroll up in the logs: with RUST_BACKTRACE=1 the originating panic from the transform task precedes this one and names the real culprit","Identify the transform via the request span and reproduce the triggering event shape in isolation","Fix or guard the offending transform (filter/re-route the events that trigger it)","Upgrade Vector and retest - fanout/concurrency handling improves across releases"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// The transform task's panic kills the topology task; supervise the process and alert:\n//   systemd: Restart=on-failure, Environment=RUST_BACKTRACE=1\n// Embedding: treat JoinError::is_panic() as a crash-loop with backoff and alerting,\n// and always pull the FIRST panic in the logs (the transform's own) as root cause.","preventionTips":["Always run with RUST_BACKTRACE=1 so the first panic is actionable","Canary new event sources and transforms in staging with production-shaped data","Watch internal_metrics for transform task restarts as an early signal"],"tags":["rust","vector","topology","transform","fanout","panic","join-error","concurrency"],"backgroundTag":"transform-task-panic","analyzedSha":"3708c39b12a93212ed8b8d7510b4cc7769cb5864","analyzedAt":"2026-08-20T07:02:18.786Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T20:17:18.057Z"}