{"record":{"id":"a2e2f16c4878a1b2","repo":"dbt-labs/dbt-core","slug":"parquet-writer-is-not-initialized","errorCode":null,"errorMessage":"Parquet writer is not initialized","messagePattern":"Parquet writer is not initialized","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-tracing/src/layers/parquet_writer.rs","lineNumber":92,"sourceCode":"        self.buffer.push(record);\n\n        Ok(())\n    }\n\n    fn flush_batch(&mut self) -> TracingResult<()> {\n        if self.buffer.is_empty() {\n            return Ok(());\n        }\n\n        // Serialize records to Arrow RecordBatch\n        let record_batch = serialize_to_arrow(&self.buffer, &self.arrow_schemas)\n            .map_err(|e| TracingError::io(format!(\"Failed to serialize to Arrow: {}\", e)))?;\n\n        // Write the batch\n        let Some(ref mut writer) = self.parquet_writer else {\n            // Should not be possible, since we ensure that parquet_writer is Some in new()\n            // and we only take it in finalize() after flushing\n            unreachable!(\"Parquet writer is not initialized\");\n        };\n\n        writer\n            .write(&record_batch)\n            .map_err(|e| TracingError::io(format!(\"Failed to write Parquet batch: {}\", e)))?;\n\n        // Flush if we are over memory limit\n        if writer.memory_size() >= PARQUET_WRITER_MEMORY_LIMIT {\n            writer\n                .flush()\n                .map_err(|e| TracingError::io(format!(\"Failed to flush Parquet writer: {}\", e)))?;\n        }\n\n        // Clear buffer for reuse (truncate avoids reallocation)\n        self.buffer.truncate(0);\n\n        Ok(())\n    }","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-tracing/src/layers/parquet_writer.rs#L74-L110","documentation":"Parquet trace writer invariant panic. ParquetWriterLayer guarantees parquet_writer is Some from construction and only takes it during finalize() after a flush, so flush_batch should always see it. Panicking here means the writer was consumed or the layer was used after finalize.","triggerScenarios":"write_record or finalize calling flush_batch after finalize() has already taken the parquet_writer, or a construction path that leaves parquet_writer as None.","commonSituations":"Double-finalize of the tracing subscriber; writing trace records after the tracing pipeline was shut down; reuse of a finalized writer layer.","solutions":["Ensure finalize() is called exactly once, after all records are written","Do not emit tracing events after the parquet layer has been finalized","If custom lifecycle code exists, keep parquet_writer Some until the final flush completes","Report a bug with a reproducer if triggered through normal usage"],"exampleFix":"// before\nlet Some(ref mut writer) = self.parquet_writer else {\n    unreachable!(\"Parquet writer is not initialized\");\n};\n// after\nlet Some(ref mut writer) = self.parquet_writer else {\n    eprintln!(\"parquet writer already finalized; dropping batch\");\n    return Ok(());\n};","handlingStrategy":"try-catch","validationCode":"// check lifecycle before writing\nassert!(!self.finalized, \"cannot write records after finalize()\");","typeGuard":null,"tryCatchPattern":"// panics are not recoverable via catch_unwind here; ensure lifecycle:\nmatch std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| layer.write_record(rec))) {\n    Ok(v) => v,\n    Err(_) => eprintln!(\"trace record dropped: writer finalized\"),\n}","preventionTips":["Call finalize() exactly once at shutdown","Never emit tracing events after subscriber teardown","Do not clone or reuse writer layers across lifecycles"],"tags":["tracing","parquet","lifecycle","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}