{"record":{"id":"5eed94fe0c3d003f","repo":"astrid-runtime/astrid","slug":"named-pipe-client-disconnected-before-transport-au","errorCode":null,"errorMessage":"named-pipe client disconnected before transport authentication","messagePattern":"named-pipe client disconnected before transport authentication","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/astrid-core/src/local_transport/windows.rs","lineNumber":312,"sourceCode":"    };\n    require_current_user_effective_client(&stream)?;\n    // Effective-token impersonation above is the authorization boundary.\n    // The process-token check is independent defense in depth and pins the\n    // client process object while re-reading the pipe-reported PID.\n    let peer = require_current_user_process_peer(&stream)?;\n    validate_pipe_security(stream_handle(&stream)?)?;\n    peer.ensure_still_peer(&stream)?;\n    Ok(stream)\n}\n\nfn pre_authentication_eof(source: Option<&io::Error>) -> io::Error {\n    let message = match source {\n        Some(source) => {\n            format!(\"named-pipe client disconnected before transport authentication: {source}\")\n        },\n        None => \"named-pipe client disconnected before transport authentication\".to_string(),\n    };\n    io::Error::new(io::ErrorKind::UnexpectedEof, message)\n}\n\nfn is_pre_authentication_disconnect(error: &io::Error) -> bool {\n    matches!(\n        error.raw_os_error().map(i32::cast_unsigned),\n        Some(ERROR_BROKEN_PIPE | ERROR_NO_DATA | ERROR_PIPE_NOT_CONNECTED)\n    )\n}\n\npub(super) fn split(\n    stream: LocalStream,\n) -> (\n    tokio::io::ReadHalf<LocalStream>,\n    tokio::io::WriteHalf<LocalStream>,\n) {\n    tokio::io::split(stream)\n}\n","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/local_transport/windows.rs#L294-L330","documentation":"On Windows, if a named-pipe client closes (or the pipe breaks) before completing transport-level authentication, Astrid surfaces an io::ErrorKind::UnexpectedEof error via pre_authentication_eof(), optionally chaining the underlying OS error in the message. This distinguishes an early, unauthenticated disconnect from post-auth protocol errors; is_pre_authentication_disconnect classifies ERROR_BROKEN_PIPE / ERROR_NO_DATA / ERROR_PIPE_NOT_CONNECTED as this case.","triggerScenarios":"accept() reads from a freshly connected pipe client and the client process exits or its connection breaks (ERROR_BROKEN_PIPE, ERROR_NO_DATA, ERROR_PIPE_NOT_CONNECTED) before the handshake/auth exchange finishes.","commonSituations":"A health-check or port scanner connects and immediately closes; the client crashed or was killed mid-handshake; a client with the wrong protocol gives up before authenticating; network/pipe interruption during startup.","solutions":["Treat this as a benign remote-side disconnect: server-side, catch io::ErrorKind::UnexpectedEof and continue the accept loop instead of failing","Investigate the client: ensure it runs the full authentication handshake before dropping the connection","If it happens at scale, check for scanners/load balancers probing the pipe and exclude the endpoint from probing"],"exampleFix":"// server accept loop\nmatch listener.accept().await {\n    Ok((stream, _)) => spawn_auth(stream),\n    Err(e) if is_pre_authentication_disconnect(&e) => continue, // client hung up early\n    Err(e) => return Err(e),\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match listener.accept().await {\n    Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => continue, // client hung up pre-auth\n    other => other?,\n}","preventionTips":["Treat early client disconnects as expected noise: log at debug, keep the accept loop alive","Ensure clients perform the full authentication handshake before dropping","Exclude the pipe endpoint from health-checkers/scanners that connect-and-close"],"tags":["windows","named-pipes","ipc","authentication","disconnect"],"backgroundTag":"broken-pipe","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}