Skip to main content

arrow_schema/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5//! Defines `ArrowError` for representing failures in various Arrow operations.
6use std::fmt::{Debug, Display, Formatter};
7use std::io::Write;
8
9use std::error::Error;
10
11/// Many different operations in the `arrow` crate return this error type.
12#[derive(Debug)]
13pub enum ArrowError {
14    /// Returned when functionality is not yet available.
15    NotYetImplemented(String),
16    /// Wraps an external error.
17    ExternalError(Box<dyn Error + Send + Sync>),
18    /// Error during casting from one type to another.
19    CastError(String),
20    /// Memory or buffer error.
21    MemoryError(String),
22    /// Error during parsing from a string.
23    ParseError(String),
24    /// Error during schema-related operations.
25    SchemaError(String),
26    /// Error during computation.
27    ComputeError(String),
28    /// Error during division by zero.
29    DivideByZero,
30    /// Error when an arithmetic operation overflows.
31    ArithmeticOverflow(String),
32    /// Error during CSV-related operations.
33    CsvError(String),
34    /// Error during JSON-related operations.
35    JsonError(String),
36    /// Error during Avro-related operations.
37    AvroError(String),
38    /// Error during IO operations.
39    IoError(String, std::io::Error),
40    /// Error during IPC operations in `arrow-ipc` or `arrow-flight`.
41    IpcError(String),
42    /// Error indicating that an unexpected or bad argument was passed to a function.
43    InvalidArgumentError(String),
44    /// Error during Parquet operations.
45    ParquetError(String),
46    /// Error during import or export to/from the C Data Interface
47    CDataInterface(String),
48    /// Error when a dictionary key is bigger than the key type
49    DictionaryKeyOverflowError,
50    /// Error when a run-end index is bigger than the run-end type
51    RunEndIndexOverflowError,
52    /// Error when the offset overflows.
53    OffsetOverflowError(usize),
54}
55
56impl ArrowError {
57    /// Wraps an external error in an `ArrowError`.
58    pub fn from_external_error(error: Box<dyn Error + Send + Sync>) -> Self {
59        Self::ExternalError(error)
60    }
61}
62
63impl From<std::io::Error> for ArrowError {
64    fn from(error: std::io::Error) -> Self {
65        ArrowError::IoError(error.to_string(), error)
66    }
67}
68
69impl From<std::str::Utf8Error> for ArrowError {
70    fn from(error: std::str::Utf8Error) -> Self {
71        ArrowError::ParseError(error.to_string())
72    }
73}
74
75impl From<std::string::FromUtf8Error> for ArrowError {
76    fn from(error: std::string::FromUtf8Error) -> Self {
77        ArrowError::ParseError(error.to_string())
78    }
79}
80
81impl<W: Write> From<std::io::IntoInnerError<W>> for ArrowError {
82    fn from(error: std::io::IntoInnerError<W>) -> Self {
83        ArrowError::IoError(error.to_string(), error.into())
84    }
85}
86
87impl Display for ArrowError {
88    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
89        match self {
90            ArrowError::NotYetImplemented(source) => {
91                write!(f, "Not yet implemented: {source}")
92            }
93            ArrowError::ExternalError(source) => write!(f, "External error: {source}"),
94            ArrowError::CastError(desc) => write!(f, "Cast error: {desc}"),
95            ArrowError::MemoryError(desc) => write!(f, "Memory error: {desc}"),
96            ArrowError::ParseError(desc) => write!(f, "Parser error: {desc}"),
97            ArrowError::SchemaError(desc) => write!(f, "Schema error: {desc}"),
98            ArrowError::ComputeError(desc) => write!(f, "Compute error: {desc}"),
99            ArrowError::ArithmeticOverflow(desc) => write!(f, "Arithmetic overflow: {desc}"),
100            ArrowError::DivideByZero => write!(f, "Divide by zero error"),
101            ArrowError::AvroError(desc) => write!(f, "Avro error: {desc}"),
102            ArrowError::CsvError(desc) => write!(f, "Csv error: {desc}"),
103            ArrowError::JsonError(desc) => write!(f, "Json error: {desc}"),
104            ArrowError::IoError(desc, _) => write!(f, "Io error: {desc}"),
105            ArrowError::IpcError(desc) => write!(f, "Ipc error: {desc}"),
106            ArrowError::InvalidArgumentError(desc) => {
107                write!(f, "Invalid argument error: {desc}")
108            }
109            ArrowError::ParquetError(desc) => {
110                write!(f, "Parquet argument error: {desc}")
111            }
112            ArrowError::CDataInterface(desc) => {
113                write!(f, "C Data interface error: {desc}")
114            }
115            ArrowError::DictionaryKeyOverflowError => {
116                write!(f, "Dictionary key bigger than the key type")
117            }
118            ArrowError::RunEndIndexOverflowError => {
119                write!(f, "Run end index bigger than the run-end type")
120            }
121            ArrowError::OffsetOverflowError(offset) => {
122                write!(f, "Offset overflow error: {offset}")
123            }
124        }
125    }
126}
127
128impl Error for ArrowError {
129    fn source(&self) -> Option<&(dyn Error + 'static)> {
130        match self {
131            ArrowError::ExternalError(source) => Some(source.as_ref()),
132            ArrowError::IoError(_, source) => Some(source),
133            _ => None,
134        }
135    }
136}
137
138#[cfg(test)]
139mod test {
140    use super::*;
141
142    #[test]
143    fn error_source() {
144        let e1 = ArrowError::DivideByZero;
145        assert!(e1.source().is_none());
146
147        // one level of wrapping
148        let e2 = ArrowError::ExternalError(Box::new(e1));
149        let source = e2.source().unwrap().downcast_ref::<ArrowError>().unwrap();
150        assert!(matches!(source, ArrowError::DivideByZero));
151
152        // two levels of wrapping
153        let e3 = ArrowError::ExternalError(Box::new(e2));
154        let source = e3
155            .source()
156            .unwrap()
157            .downcast_ref::<ArrowError>()
158            .unwrap()
159            .source()
160            .unwrap()
161            .downcast_ref::<ArrowError>()
162            .unwrap();
163
164        assert!(matches!(source, ArrowError::DivideByZero));
165    }
166}