{"record":{"id":"d96095b61b9dc15e","repo":"tracel-ai/burn","slug":"writer-present-checked-above","errorCode":null,"errorMessage":"writer present (checked above)","messagePattern":"writer present \\(checked above\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"crates/burn-remote/src/client/service.rs","lineNumber":684,"sourceCode":"            return;\n        }\n        self.closed = true;\n\n        // If we never connected, there's no server-side session to close and no writer to\n        // drain — whatever was buffered never had a connection to go out on, so just drop it.\n        if self.writer.is_none() {\n            return;\n        }\n\n        // Best-effort teardown: append Close to whatever's still buffered and let the\n        // writer drain + flush it before we join the task, so the runtime isn't torn down\n        // mid-send. Serialization happens in the writer task now, so Drop can't panic on it.\n        self.batch.push(RemoteMessage::Close(self.session_id));\n        let batch = self.batch.take();\n        let writer = self\n            .writer\n            .as_mut()\n            .expect(\"writer present (checked above)\");\n        writer.shutdown(&self.executor, Some(batch));\n    }\n}\n","sourceCodeStart":666,"sourceCodeEnd":688,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-remote/src/client/service.rs#L666-L688","documentation":"In `Drop for RemoteService`, the code checks `self.writer.is_none()` and returns early, then unwraps the writer with expect; the expect documents that the check above guarantees `Some`. This is a pure internal invariant assertion and unreachable in a stock build — it can only fire if the drop logic itself is altered (e.g. in a fork) or mutated concurrently during teardown.","triggerScenarios":"Unreachable in stock code; possible only if a fork removes/reorders the `if self.writer.is_none() { return; }` guard, or if aliasing mutation sets writer to None between the check and the expect (would require unsafe/interior mutability misuse).","commonSituations":"Maintainers or fork authors modifying the Drop implementation; custom writer types with Drop impls that reset service state during teardown.","solutions":["Do not modify the Drop guard ordering; keep the `is_none()` early-return immediately before the expect.","If you maintain a fork, diff your Drop impl against upstream burn-remote service.rs.","If you genuinely hit this on stock code, file a bug with the burn version and a reproduction."],"exampleFix":"// before (fork that removed the guard)\nfn drop(&mut self) {\n    let writer = self.writer.as_mut().expect(\"writer present (checked above)\");\n// after: restore the guard\nfn drop(&mut self) {\n    if self.writer.is_none() { return; }\n    let writer = self.writer.as_mut().expect(\"writer present (checked above)\");","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"// Mirrors the drop guard; use before teardown in forked code:\nfn writer_ready(service: &RemoteService) -> bool { service.is_connected() } // writer.is_some()","tryCatchPattern":"// Drop impls must not panic; if you fork, guard explicitly:\nif let Some(writer) = self.writer.as_mut() { writer.shutdown(&self.executor, Some(batch)); }","preventionTips":["Never reorder the is_none() guard and expect inside Drop.","Prefer `if let Some(writer) = ...` over expect in teardown code you own.","Keep Drop logic free of side effects that could reset service state.","Test drop-during-operation paths in CI when forking burn-remote."],"tags":["panic","invariant-violation","drop","burn-remote"],"backgroundTag":"invariant-violation-panic","analyzedSha":"d16f7ba2ed0d41408189384044cc886fb4c8f957","analyzedAt":"2026-09-05T13:19:14.260Z","contentChangedAt":"2026-09-05T13:19:14.260Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}