{"record":{"id":"4ba5def18fb95e72","repo":"janhq/jan","slug":"io-error-0","errorCode":null,"errorMessage":"IO error: {0}","messagePattern":"IO error: (.+?)","errorType":"exception","errorClass":"ServerError::Io","httpStatus":null,"severity":"error","filePath":"src-tauri/plugins/tauri-plugin-llamacpp/src/error.rs","lineNumber":197,"sourceCode":"\nfn basename(path: &str) -> &str {\n    path.rsplit(['/', '\\\\']).next().unwrap_or(path)\n}\n\nfn push_library(found: &mut Vec<String>, candidate: &str) {\n    let candidate = candidate.trim_matches(['\\'', '\"', '(', ')', ',', '.'].as_ref());\n    if looks_like_library(candidate) && !found.iter().any(|f| f == candidate) {\n        found.push(candidate.to_string());\n    }\n}\n\n// Error type for server commands\n#[derive(Debug, thiserror::Error)]\npub enum ServerError {\n    #[error(transparent)]\n    Llamacpp(#[from] LlamacppError),\n\n    #[error(\"IO error: {0}\")]\n    Io(#[from] std::io::Error),\n\n    #[error(\"Tauri error: {0}\")]\n    Tauri(#[from] tauri::Error),\n\n    #[error(\"Invalid argument: {0}\")]\n    InvalidArgument(String),\n}\n\n// impl serialization for tauri\nimpl serde::Serialize for ServerError {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        let error_to_serialize: LlamacppError = match self {\n            ServerError::Llamacpp(err) => err.clone(),\n            ServerError::Io(e) => LlamacppError::new(","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/src-tauri/plugins/tauri-plugin-llamacpp/src/error.rs#L179-L215","documentation":"The ServerError::Io variant (#[from] std::io::Error) in the tauri-plugin-llamacpp plugin. Its Display is \"IO error: {0}\". When serialized for Tauri it is mapped to a LlamacppError with code IO_ERROR and message \"An input/output error occurred.\", with the io::Error string preserved in details. It covers filesystem, process-spawn, and pipe failures inside server commands.","triggerScenarios":"A command uses `?` on io::Result — reading a model file, spawning the llama-server process, writing a pidfile, or reading a pipe — and the io::Error converts into ServerError::Io.","commonSituations":"Model file path unreadable or permission denied; llama-server binary missing (also surfaces as BinaryNotFound elsewhere); pipe broken when the frontend disconnects mid-stream; disk full.","solutions":["Check file/path permissions and existence for any path the command reads or writes.","Confirm the llama-server binary is installed and executable (else expect BinaryNotFound for the dedicated case).","Handle a broken pipe gracefully if the client disconnects during streaming.","Free disk space if writes are failing."],"exampleFix":"// Rust\npub fn read_model_meta(p: String) -> ServerResult<String> {\n    let s = std::fs::read_to_string(&p)?; // io::Error -> ServerError::Io\n    Ok(s)\n}\n\n// Frontend\ncatch (e) {\n  const err = JSON.parse(e.message)\n  if (err.code === 'IO_ERROR') showFileAdvice(err.details)\n}","handlingStrategy":"try-catch","validationCode":"import { existsSync, accessSync, constants } from 'fs'\nfunction assertReadable(p: string) {\n  if (!existsSync(p)) throw new Error(`File missing: ${p}`)\n  accessSync(p, constants.R_OK)\n}","typeGuard":null,"tryCatchPattern":"try {\n  await invoke('start_server', { ... })\n} catch (e) {\n  const err = JSON.parse((e as any).message ?? '{}')\n  if (err.code === 'IO_ERROR') showFileOrPermissionsAdvice(err.details)\n  else throw e\n}","preventionTips":["Verify file existence and read permissions before invoking commands that read them.","Ensure the llama-server binary is installed and executable.","Handle broken-pipe conditions when streaming to a disconnecting client."],"tags":["rust","io","error-handling","tauri","filesystem"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}