Error Handling
Copy MarkdownMilvex uses Splode for structured error handling. All errors are typed and can be pattern matched for precise error handling.
Error Types
Milvex.Errors.Invalid
Validation and input errors. Raised when user-provided data fails validation.
Fields:
field- The field that failed validation (optional)message- Human-readable error messagecode- Error code atom (optional)context- Additional context map (optional)
Common causes:
- Invalid configuration parameters
- Schema validation failures
- Missing required fields
- Type mismatches
%Milvex.Errors.Invalid{
field: :dimension,
message: "must be a positive integer",
code: :invalid_dimension
}Milvex.Errors.Connection
Network and connection errors. Raised when connection to Milvus fails.
Fields:
reason- Error reason (string or atom)host- Target host (optional)port- Target port (optional)retriable- Whether the operation can be retried (optional)
Common causes:
- Unable to establish gRPC connection
- Connection timeout
- Network unreachable
- Connection lost during operation
%Milvex.Errors.Connection{
reason: :timeout,
host: "localhost",
port: 19530,
retriable: true
}Milvex.Errors.Grpc
Server-side errors from Milvus or gRPC layer.
Fields:
code- Error code (integer or atom)message- Error message from serverdetails- Additional details map (optional)operation- The operation that failed (optional)
Common causes:
- Milvus returns an error status code
- gRPC call fails
- Server-side validation fails
- Operation not permitted
%Milvex.Errors.Grpc{
code: 1,
message: "collection not found: movies",
operation: :search
}Milvex.Errors.Unknown
Catch-all for unexpected errors.
Fields:
error- The original errorstacktrace- Stack trace if available
Pattern Matching on Errors
Use pattern matching to handle specific error types:
case Milvex.search(conn, "movies", vectors, vector_field: "embedding") do
{:ok, results} ->
process_results(results)
{:error, %Milvex.Errors.Connection{retriable: true} = error} ->
Logger.warning("Connection issue, retrying: #{Exception.message(error)}")
retry_operation()
{:error, %Milvex.Errors.Connection{} = error} ->
Logger.error("Connection failed: #{Exception.message(error)}")
{:error, :connection_failed}
{:error, %Milvex.Errors.Grpc{code: code} = error} ->
Logger.error("Milvus error (#{code}): #{Exception.message(error)}")
handle_milvus_error(code)
{:error, %Milvex.Errors.Invalid{field: field} = error} ->
Logger.error("Validation error on #{field}: #{Exception.message(error)}")
{:error, :invalid_input}
{:error, error} ->
Logger.error("Unexpected error: #{Exception.message(error)}")
{:error, :unknown}
endUsing Bang Functions
All Milvex operations have bang variants that raise on error:
# Returns {:ok, result} or {:error, error}
{:ok, results} = Milvex.search(conn, "movies", vectors, vector_field: "embedding")
# Raises on error
results = Milvex.search!(conn, "movies", vectors, vector_field: "embedding")Use bang functions when:
- Errors should halt execution
- In scripts or one-off operations
- When the calling code has a
try/rescueblock
Use regular functions when:
- You need to handle specific error cases
- Building resilient applications
- Implementing retry logic
Error Messages
All error types implement Exception.message/1:
case Milvex.insert(conn, "movies", data) do
{:ok, result} ->
{:ok, result}
{:error, error} ->
Logger.error(Exception.message(error))
{:error, error}
endCommon Error Scenarios
Collection Not Found
case Milvex.search(conn, "nonexistent", vectors, vector_field: "embedding") do
{:error, %Milvex.Errors.Grpc{message: msg}} when msg =~ "not found" ->
{:error, :collection_not_found}
other ->
other
endConnection Timeout
case Milvex.Connection.start_link(host: "unreachable.host", timeout: 5000) do
{:ok, conn} ->
{:ok, conn}
{:error, %Milvex.Errors.Connection{reason: :timeout}} ->
{:error, :connection_timeout}
{:error, %Milvex.Errors.Connection{reason: reason}} ->
{:error, {:connection_failed, reason}}
endInvalid Schema
case Milvex.Schema.build(name: "test", fields: []) do
{:ok, schema} ->
{:ok, schema}
{:error, %Milvex.Errors.Invalid{field: :fields}} ->
{:error, :no_fields_defined}
endRetry Strategies
For transient errors, implement retry logic:
defmodule MyApp.Milvus do
def search_with_retry(conn, collection, vectors, opts, retries \\ 3) do
case Milvex.search(conn, collection, vectors, opts) do
{:ok, results} ->
{:ok, results}
{:error, %Milvex.Errors.Connection{retriable: true}} when retries > 0 ->
Process.sleep(1000)
search_with_retry(conn, collection, vectors, opts, retries - 1)
{:error, error} ->
{:error, error}
end
end
endThe connection itself handles reconnection automatically with exponential backoff, but application-level retries may be needed for transient operation failures.