{"record":{"id":"b9aeb472f9de38a9","repo":"diem/diem","slug":"client-0-is-closed","errorCode":null,"errorMessage":"Client#{0} is closed","messagePattern":"Client#(.+?) is closed","errorType":"error_code","errorClass":"StreamError","httpStatus":null,"severity":"warning","filePath":"json-rpc/src/stream_rpc/errors.rs","lineNumber":10,"sourceCode":"// Copyright (c) The Diem Core Contributors\n// SPDX-License-Identifier: Apache-2.0\n\nuse thiserror::Error;\n\n#[derive(Debug, Error)]\npub enum StreamError {\n    #[error(\"Could not convert {0} to string\")]\n    CouldNotStringifyMessage(String),\n    #[error(\"Client#{0} is closed\")]\n    ClientAlreadyClosed(u64),\n    #[error(\"Received disconnect request message from client\")]\n    ClientWantsToDisconnect,\n    #[error(\"Transport error: {0}\")]\n    TransportError(String),\n}\n","sourceCodeStart":1,"sourceCodeEnd":17,"githubUrl":"https://github.com/diem/diem/blob/fc4714a8ea273b6efe8b13dbce72ea60aad9a16c/json-rpc/src/stream_rpc/errors.rs#L1-L17","documentation":"`StreamError::ClientAlreadyClosed(u64)` indicates an operation was attempted on a streaming-RPC client identified by the given id, but that client's stream is already closed. Once a client disconnects or its stream is torn down, further sends/operations on it are rejected with this error.","triggerScenarios":"Sending a message or notification to a subscribed client after it disconnected or its channel was dropped/closed; racing a close with an in-flight send on the stream-rpc layer.","commonSituations":"Clients dropping WebSocket connections mid-subscription; server-side timeouts closing streams while notifications are still queued; double-close attempts during shutdown.","solutions":["Treat it as benign: check client liveness before sending and skip/log when already closed.","Track client connection state in a registry and remove closed clients from notification fan-out lists.","Synchronize close/send paths (e.g., use a single owner task per client) to avoid races between closing and sending.","Ensure clients reconnect and re-subscribe; the id in the message identifies the stale client."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_client_closed(err: &StreamError, client_id: u64) -> bool {\n    matches!(err, StreamError::ClientAlreadyClosed(id) if *id == client_id)\n}","tryCatchPattern":"match notify_client(client_id, &msg) {\n    Err(StreamError::ClientAlreadyClosed(id)) => {\n        debug!(\"client#{} already closed; dropping notification\", id);\n        registry.remove(id);\n    }\n    Err(e) => error!(\"notify failed: {}\", e),\n    Ok(_) => {}\n}","preventionTips":["Maintain a client registry and remove entries as soon as streams close.","Route all sends through a per-client owner task so close/send races are eliminated.","Treat sends to closed clients as benign and never retry them."],"tags":["rust","json-rpc","streaming","websocket","connection-lifecycle"],"backgroundTag":"stream-already-closed","analyzedSha":"fc4714a8ea273b6efe8b13dbce72ea60aad9a16c","analyzedAt":"2026-09-04T21:07:05.890Z","contentChangedAt":"2026-09-04T21:07:05.890Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}