Skip to main content

vllm_cpp/
error.rs

1use std::ffi::CStr;
2use std::fmt;
3
4use vllm_cpp_sys as ffi;
5
6/// An error returned while resolving a model from the Hugging Face Hub.
7///
8/// External transport errors are converted to contextual strings so this type
9/// remains stable, cloneable, and comparable.
10#[derive(Clone, Debug, Eq, PartialEq)]
11#[non_exhaustive]
12pub enum HuggingFaceError {
13    /// A repository, revision, or filename is invalid.
14    InvalidInput { message: String },
15    /// The requested revision is not present in the selected local cache.
16    CacheMiss { message: String },
17    /// A repository snapshot lacks required runtime files or metadata.
18    Incomplete { message: String },
19    /// A Hugging Face API or download operation failed.
20    Hub { message: String },
21    /// A local cache operation failed.
22    Io { message: String },
23}
24
25impl fmt::Display for HuggingFaceError {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        match self {
28            Self::InvalidInput { message } => write!(f, "invalid Hugging Face model: {message}"),
29            Self::CacheMiss { message } => write!(f, "Hugging Face cache miss: {message}"),
30            Self::Incomplete { message } => {
31                write!(f, "incomplete Hugging Face snapshot: {message}")
32            }
33            Self::Hub { message } => write!(f, "Hugging Face Hub failure: {message}"),
34            Self::Io { message } => write!(f, "Hugging Face cache I/O failure: {message}"),
35        }
36    }
37}
38
39impl std::error::Error for HuggingFaceError {}
40
41/// An error returned by the safe vllm.cpp wrapper.
42#[derive(Clone, Debug, Eq, PartialEq)]
43#[non_exhaustive]
44pub enum Error {
45    /// The loaded native library does not match the generated C ABI.
46    AbiMismatch { expected: i32, actual: i32 },
47    /// Native code rejected caller input.
48    InvalidArgument { message: String },
49    /// The model, tokenizer, configuration, or weights could not be loaded.
50    ModelLoad { message: String },
51    /// Native generation failed at runtime.
52    Runtime { message: String },
53    /// Native code reported an unclassified failure.
54    NativeUnknown { message: String },
55    /// Native code returned a status unknown to these bindings.
56    UnknownStatus { status: u32, message: String },
57    /// A value cannot cross the C boundary because it contains a NUL byte.
58    InteriorNul { field: &'static str },
59    /// A platform path cannot be represented by the native UTF-8 API.
60    PathEncoding,
61    /// Native code returned bytes that are not valid UTF-8.
62    InvalidUtf8 { field: &'static str },
63    /// An asynchronous output callback panicked.
64    CallbackPanicked,
65    /// A custom logits processor panicked.
66    LogitsProcessorPanicked,
67    /// A request operation was attempted from that request's callback thread.
68    RequestCallbackThread { operation: &'static str },
69    /// A Rust-side parameter cannot be represented by the native API.
70    InvalidConfiguration { message: String },
71    /// JSON serialization or parsing failed.
72    Json {
73        context: &'static str,
74        message: String,
75    },
76}
77
78impl fmt::Display for Error {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        match self {
81            Self::AbiMismatch { expected, actual } => {
82                write!(
83                    f,
84                    "vllm.cpp ABI mismatch: expected {expected}, found {actual}"
85                )
86            }
87            Self::InvalidArgument { message } => write!(f, "invalid argument: {message}"),
88            Self::ModelLoad { message } => write!(f, "model load failed: {message}"),
89            Self::Runtime { message } => write!(f, "vllm.cpp runtime failure: {message}"),
90            Self::NativeUnknown { message } => write!(f, "unknown native failure: {message}"),
91            Self::UnknownStatus { status, message } => {
92                write!(f, "unknown native status {status}: {message}")
93            }
94            Self::InteriorNul { field } => write!(f, "{field} contains an interior NUL byte"),
95            Self::PathEncoding => write!(f, "path cannot be represented by the native API"),
96            Self::InvalidUtf8 { field } => write!(f, "native {field} is not valid UTF-8"),
97            Self::CallbackPanicked => write!(f, "asynchronous request callback panicked"),
98            Self::LogitsProcessorPanicked => write!(f, "custom logits processor panicked"),
99            Self::RequestCallbackThread { operation } => {
100                write!(
101                    f,
102                    "cannot {operation} a request from its own callback thread"
103                )
104            }
105            Self::InvalidConfiguration { message } => {
106                write!(f, "invalid configuration: {message}")
107            }
108            Self::Json { context, message } => write!(f, "{context}: {message}"),
109        }
110    }
111}
112
113impl std::error::Error for Error {}
114
115pub(crate) fn status_result(status: ffi::vllm_status) -> Result<(), Error> {
116    if status == ffi::vllm_status_VLLM_OK {
117        return Ok(());
118    }
119
120    // The native diagnostic is thread-local and valid only until the next C API
121    // call on this thread, so copy it before doing any other FFI work.
122    let message = unsafe {
123        let pointer = ffi::vllm_last_error();
124        if pointer.is_null() {
125            String::new()
126        } else {
127            CStr::from_ptr(pointer).to_string_lossy().into_owned()
128        }
129    };
130    let error = match status {
131        ffi::vllm_status_VLLM_ERR_INVALID_ARGUMENT => Error::InvalidArgument { message },
132        ffi::vllm_status_VLLM_ERR_MODEL_LOAD => Error::ModelLoad { message },
133        ffi::vllm_status_VLLM_ERR_RUNTIME => Error::Runtime { message },
134        ffi::vllm_status_VLLM_ERR_UNKNOWN => Error::NativeUnknown { message },
135        status => Error::UnknownStatus { status, message },
136    };
137    Err(error)
138}
139
140pub(crate) fn invalid_configuration(message: impl Into<String>) -> Error {
141    Error::InvalidConfiguration {
142        message: message.into(),
143    }
144}