Skip to main content

google_cloud_bigquery/write/
error.rs

1// Copyright 2026 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::Error;
16use crate::model::{RowError, StorageError};
17use google_cloud_gax::error::rpc::Status;
18
19/// Represents an error that can occur when appending rows.
20#[derive(thiserror::Error, Debug)]
21#[non_exhaustive]
22pub enum AppendError {
23    /// The underlying RPC failed.
24    #[non_exhaustive]
25    #[error("the operation failed. RPC error: {source}")]
26    Rpc {
27        /// The error returned by the service for the request.
28        #[from]
29        #[source]
30        source: Error,
31    },
32
33    /// Certain rows have errors.
34    #[non_exhaustive]
35    #[error(
36        "there was an error for the following rows. No rows in the batch were appended. You can remove the bad rows and retry the request. Status: {status:?}, Rows: {row_errors:?}"
37    )]
38    RowErrors {
39        /// The status returned by the service for the request.
40        status: Status,
41        /// The row-level errors reported by the service.
42        row_errors: Vec<RowError>,
43    },
44
45    /// The `AppendRows` stream closed unexpectedly.
46    #[error(
47        "the `AppendRows` stream closed unexpectedly and the client library could not recover."
48    )]
49    UnexpectedEndOfStream,
50}
51
52pub(crate) type AppendResult<T> = std::result::Result<T, AppendError>;
53
54/// Represents an error that can occur when committing a pending write stream.
55#[derive(thiserror::Error, Debug)]
56#[non_exhaustive]
57pub enum CommitError {
58    /// The underlying RPC failed.
59    #[non_exhaustive]
60    #[error("the operation failed. RPC error: {source}")]
61    Rpc {
62        /// The error returned by the service for the request.
63        #[from]
64        #[source]
65        source: Error,
66    },
67
68    /// The stream could not be committed.
69    #[non_exhaustive]
70    #[error(
71        "the service failed to commit the stream. No rows in the stream were committed. Stream errors: {stream_errors:?}"
72    )]
73    FailedTransaction {
74        /// The stream-level errors reported by the service.
75        stream_errors: Vec<StorageError>,
76    },
77}
78
79/// Represents an error that can occur when building a writer.
80#[derive(thiserror::Error, Debug)]
81#[non_exhaustive]
82pub enum WriterBuilderError {
83    /// The targeted write stream was a different stream type than expected.
84    #[non_exhaustive]
85    #[error("stream type mismatch: requested {expected}, but matched resource yields {actual}")]
86    TypeMismatch {
87        /// The expected stream type.
88        expected: String,
89        /// The actual stream type returned by the service.
90        actual: String,
91    },
92
93    /// The underlying RPC failed.
94    #[non_exhaustive]
95    #[error("the operation failed. RPC error: {source}")]
96    Rpc {
97        /// The error returned by the service for the request.
98        #[from]
99        #[source]
100        source: Error,
101    },
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use crate::model::storage_error::StorageErrorCode;
108    use google_cloud_gax::error::rpc::{Code, Status};
109
110    #[test]
111    fn append_error_rpc_debug() {
112        let e = AppendError::Rpc {
113            source: Error::service(
114                Status::default()
115                    .set_code(Code::FailedPrecondition)
116                    .set_message("inner fail"),
117            ),
118        };
119        let fmt = format!("{e}");
120        assert!(fmt.contains("operation failed."), "{fmt}");
121        assert!(fmt.contains("inner fail"), "{fmt}");
122    }
123
124    #[test]
125    fn commit_error_display() {
126        let e = CommitError::Rpc {
127            source: Error::service(
128                Status::default()
129                    .set_code(Code::Unavailable)
130                    .set_message("inner fail"),
131            ),
132        };
133        let fmt = format!("{e}");
134        assert!(fmt.contains("operation failed."), "{fmt}");
135        assert!(fmt.contains("inner fail"), "{fmt}");
136
137        let e = CommitError::FailedTransaction {
138            stream_errors: vec![
139                StorageError::new()
140                    .set_code(StorageErrorCode::InvalidStreamState)
141                    .set_entity("projects/p/datasets/d/tables/t/streams/s")
142                    .set_error_message("stream not finalized"),
143            ],
144        };
145        let fmt = format!("{e}");
146        assert!(fmt.contains("failed to commit the stream"), "{fmt}");
147        assert!(fmt.contains("stream not finalized"), "{fmt}");
148    }
149}