Skip to main content

feagi_services/types/
errors.rs

1// Copyright 2025 Neuraville Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4/*!
5Service layer error types.
6
7Transport-agnostic errors that can be mapped to HTTP status codes,
8ZMQ error codes, or embedded error codes by adapters.
9
10Copyright 2025 Neuraville Inc.
11Licensed under the Apache License, Version 2.0
12*/
13
14use thiserror::Error;
15
16/// Service layer errors (transport-agnostic)
17#[derive(Error, Debug, Clone)]
18pub enum ServiceError {
19    /// Resource not found (404 in HTTP, NOT_FOUND in ZMQ)
20    #[error("Not found: {resource} with id '{id}'")]
21    NotFound { resource: String, id: String },
22
23    /// Invalid input parameters (400 in HTTP, BAD_REQUEST in ZMQ)
24    #[error("Invalid input: {0}")]
25    InvalidInput(String),
26
27    /// Resource already exists (409 in HTTP, CONFLICT in ZMQ)
28    #[error("Already exists: {resource} with id '{id}'")]
29    AlreadyExists { resource: String, id: String },
30
31    /// Policy or constraint conflict, e.g. region IO designation vs connectivity (409 in HTTP)
32    #[error("Conflict: {0}")]
33    Conflict(String),
34
35    /// Operation not permitted (403 in HTTP, FORBIDDEN in ZMQ)
36    #[error("Operation not permitted: {0}")]
37    Forbidden(String),
38
39    /// Internal service error (500 in HTTP, INTERNAL_ERROR in ZMQ)
40    #[error("Internal error: {0}")]
41    Internal(String),
42
43    /// Backend error (BDU, NPU, Evo)
44    #[error("Backend error: {0}")]
45    Backend(String),
46
47    /// State inconsistency
48    #[error("State error: {0}")]
49    StateError(String),
50
51    /// Invalid state for operation (e.g., trying to pause when not running)
52    #[error("Invalid state: {0}")]
53    InvalidState(String),
54
55    /// Not yet implemented
56    #[error("Not implemented: {0}")]
57    NotImplemented(String),
58}
59
60/// Result type for service operations
61pub type ServiceResult<T> = Result<T, ServiceError>;
62
63// ============================================================================
64// ERROR CONVERSIONS FROM BACKEND
65// ============================================================================
66
67impl From<feagi_npu_neural::types::FeagiError> for ServiceError {
68    fn from(err: feagi_npu_neural::types::FeagiError) -> Self {
69        match err {
70            feagi_npu_neural::types::FeagiError::CorticalAreaNotFound(_) => {
71                ServiceError::NotFound {
72                    resource: "CorticalArea".to_string(),
73                    id: err.to_string(),
74                }
75            }
76            feagi_npu_neural::types::FeagiError::InvalidArea(msg) => {
77                ServiceError::InvalidInput(msg)
78            }
79            feagi_npu_neural::types::FeagiError::InvalidRegion(msg) => {
80                ServiceError::InvalidInput(msg)
81            }
82            _ => ServiceError::Backend(err.to_string()),
83        }
84    }
85}
86
87impl From<feagi_structures::FeagiDataError> for ServiceError {
88    fn from(err: feagi_structures::FeagiDataError) -> Self {
89        ServiceError::InvalidInput(err.to_string())
90    }
91}
92
93impl From<feagi_brain_development::BduError> for ServiceError {
94    fn from(err: feagi_brain_development::BduError) -> Self {
95        match err {
96            feagi_brain_development::BduError::InvalidArea(msg) => ServiceError::InvalidInput(msg),
97            feagi_brain_development::BduError::InvalidGenome(msg) => {
98                ServiceError::InvalidInput(msg)
99            }
100            feagi_brain_development::BduError::InvalidMorphology(msg) => {
101                ServiceError::InvalidInput(msg)
102            }
103            feagi_brain_development::BduError::RegionIoPolicyViolation(msg) => {
104                ServiceError::Conflict(msg)
105            }
106            _ => ServiceError::Backend(err.to_string()),
107        }
108    }
109}
110
111impl From<feagi_evolutionary::EvoError> for ServiceError {
112    fn from(err: feagi_evolutionary::EvoError) -> Self {
113        match err {
114            feagi_evolutionary::EvoError::InvalidGenome(msg) => ServiceError::InvalidInput(msg),
115            feagi_evolutionary::EvoError::InvalidArea(msg) => ServiceError::InvalidInput(msg),
116            _ => ServiceError::Backend(err.to_string()),
117        }
118    }
119}