blob: fe5d1ca8b4839858051d8ac3753e337a473b9544 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
defmodule Fluss.Error do
@moduledoc """
Structured error returned from Fluss operations.
Fields:
* `:code` — stable atom for pattern matching.
* `:error_code` — raw integer code. Protocol codes `0..57`, `-1` for
`:unknown_server_error`, `-2` for `:client_error`.
* `:message` — human-readable description.
Also an exception, so `raise err` works.
`:client_error` covers any failure that didn't come from the server API
(bad input, transport, I/O, decode, consumed write handle, etc.) and is
not retriable, matching the Python and C++ bindings.
"""
defexception [:code, :error_code, :message]
@typedoc "Error code atom."
@type code ::
:none
| :unknown_server_error
| :network_exception
| :unsupported_version
| :corrupt_message
| :database_not_exist
| :database_not_empty
| :database_already_exist
| :table_not_exist
| :table_already_exist
| :schema_not_exist
| :log_storage_exception
| :kv_storage_exception
| :not_leader_or_follower
| :record_too_large_exception
| :corrupt_record_exception
| :invalid_table_exception
| :invalid_database_exception
| :invalid_replication_factor
| :invalid_required_acks
| :log_offset_out_of_range_exception
| :non_primary_key_table_exception
| :unknown_table_or_bucket_exception
| :invalid_update_version_exception
| :invalid_coordinator_exception
| :fenced_leader_epoch_exception
| :request_time_out
| :storage_exception
| :operation_not_attempted_exception
| :not_enough_replicas_after_append_exception
| :not_enough_replicas_exception
| :security_token_exception
| :out_of_order_sequence_exception
| :duplicate_sequence_exception
| :unknown_writer_id_exception
| :invalid_column_projection
| :invalid_target_column
| :partition_not_exists
| :table_not_partitioned_exception
| :invalid_timestamp_exception
| :invalid_config_exception
| :lake_storage_not_configured_exception
| :kv_snapshot_not_exist
| :partition_already_exists
| :partition_spec_invalid_exception
| :leader_not_available_exception
| :partition_max_num_exception
| :authenticate_exception
| :security_disabled_exception
| :authorization_exception
| :bucket_max_num_exception
| :fenced_tiering_epoch_exception
| :retriable_authenticate_exception
| :invalid_server_rack_info_exception
| :lake_snapshot_not_exist
| :lake_table_already_exist
| :ineligible_replica_exception
| :invalid_alter_table_exception
| :deletion_disabled_exception
| :client_error
@type t :: %__MODULE__{code: code(), error_code: integer(), message: String.t()}
@retriable_codes [
:network_exception,
:corrupt_message,
:schema_not_exist,
:log_storage_exception,
:kv_storage_exception,
:not_leader_or_follower,
:corrupt_record_exception,
:unknown_table_or_bucket_exception,
:request_time_out,
:storage_exception,
:not_enough_replicas_after_append_exception,
:not_enough_replicas_exception,
:leader_not_available_exception
]
@impl true
def message(%__MODULE__{code: code, message: msg}) do
"Fluss error [#{code}]: #{msg}"
end
@doc "Returns `true` if retrying the operation may succeed."
@spec retriable?(t()) :: boolean()
def retriable?(%__MODULE__{code: code}), do: code in @retriable_codes
end