콘텐츠로 이동

에러 계층 구조

Spakky Framework의 에러 클래스 계층 구조와 사용법을 설명합니다. 모든 항목은 현재 core/*/srcplugins/*/src의 실제 에러 클래스를 기준으로 합니다.


개요

Spakky는 구조화된 에러 계층을 제공합니다. 대부분의 프레임워크 에러는 AbstractSpakkyFrameworkError를 상속하며, 패키지별 기반 에러 클래스 아래에 모입니다. Provider-local 입력 검증 예외처럼 프레임워크 경계 밖에서 쓰이는 예외는 해당 섹션에 별도로 표시합니다.

flowchart TD
  Exception --> AbstractSpakkyFrameworkError

  AbstractSpakkyFrameworkError --> AbstractSpakkyApplicationError
  AbstractSpakkyFrameworkError --> AbstractSpakkyAOPError
  AbstractSpakkyFrameworkError --> AbstractSpakkyPodError
  AbstractSpakkyFrameworkError --> AbstractSpakkyDomainError
  AbstractSpakkyFrameworkError --> AbstractSpakkyPersistencyError
  AbstractSpakkyFrameworkError --> AbstractSpakkyExternalError
  AbstractSpakkyFrameworkError --> AbstractSpakkyEventError
  AbstractSpakkyFrameworkError --> AbstractSpakkyTaskError
  AbstractSpakkyFrameworkError --> AbstractSpakkyAuthError
  AbstractSpakkyFrameworkError --> AbstractSpakkyActuatorError
  AbstractSpakkyFrameworkError --> AbstractSpakkyCacheError
  AbstractSpakkyFrameworkError --> AbstractSpakkyTracingError
  AbstractSpakkyFrameworkError --> AbstractSpakkyOutboxError
  AbstractSpakkyFrameworkError --> AbstractSpakkySagaError
  AbstractSpakkyFrameworkError --> AbstractSpakkyAgentError
  AbstractSpakkyFrameworkError --> AbstractSpakkyFastAPIError
  AbstractSpakkyFrameworkError --> AbstractSpakkySqlAlchemyError
  AbstractSpakkyFrameworkError --> AbstractSpakkyCeleryError
  AbstractSpakkyFrameworkError --> AbstractSpakkyOpenTelemetryError
  AbstractSpakkyFrameworkError --> AbstractSpakkyGrpcError
  AbstractSpakkyFrameworkError --> AbstractSpakkyLoggingError
  AbstractSpakkyFrameworkError --> AbstractSpakkyOidcError
  AbstractSpakkyFrameworkError --> AbstractOpenFgaError
  AbstractSpakkyFrameworkError --> AbstractVllmError
  AbstractSpakkyFrameworkError --> CryptographyErrors[spakky-cryptography concrete errors]
  AbstractSpakkyFrameworkError --> CommonErrors[common concrete errors]
  Exception --> PolicyDocumentError

  AbstractSpakkyDomainError --> AbstractDomainValidationError
  AbstractSpakkyDomainError --> EntityNotFoundError
  AbstractSpakkyDomainError --> VersionConflictError
  AbstractSpakkyDomainError --> CannotMonkeyPatchEntityError
  AbstractSpakkyDomainError --> UnhashableFieldTypeError

  AbstractSpakkySagaError --> SagaFlowDefinitionError
  AbstractSpakkySagaError --> SagaCompensationFailedError
  AbstractSpakkySagaError --> SagaStepTimeoutError
  AbstractSpakkySagaError --> SagaParallelMergeConflictError
  AbstractSpakkySagaError --> SagaEngineNotConnectedError

  AbstractSpakkyAgentError --> AgentDefinitionError
  AbstractSpakkyAgentError --> AgentToolBindingError
  AbstractSpakkyAgentError --> AgentBootstrapError
  AbstractSpakkyAgentError --> AgentOutputGuardError
  AgentBootstrapError --> AgentPersistenceConfigurationError
  AgentBootstrapError --> AgentModelConfigurationError

  AbstractSpakkyAuthError --> AuthContextError
  AbstractSpakkyAuthError --> CredentialCarrierError
  AbstractSpakkyAuthError --> AuthenticationError
  AbstractSpakkyAuthError --> AuthorizationError
  AbstractSpakkyAuthError --> AuthContextSnapshotError
  AuthContextError --> AuthContextNotFoundError
  AuthContextError --> InvalidAuthContextValueError
  AuthorizationError --> ConflictingAuthMetadataError
  AuthorizationError --> AuthRequirementDeniedError
  AuthorizationError --> AuthRequirementProviderUnavailableError
  AuthContextSnapshotError --> MissingAuthContextSnapshotError
  AuthContextSnapshotError --> InvalidAuthContextSnapshotError
  AuthContextSnapshotError --> ExpiredAuthContextSnapshotError
  AuthContextSnapshotError --> AuthVerificationProviderUnavailableError

  AbstractSpakkyCacheError --> InvalidCacheTTLError
  AbstractSpakkyCacheError --> CacheKeyGenerationError
  AbstractSpakkyCacheError --> CacheBackendCapabilityError
  AbstractSpakkyCacheError --> AbstractSpakkyRedisError
  AbstractSpakkyRedisError --> RedisCacheOperationError
  AbstractSpakkyRedisError --> RedisCacheSerializationError
  AbstractSpakkyRedisError --> RedisCacheLockTimeoutError

  AbstractSpakkySqlAlchemyError --> AbstractSpakkySqlAlchemyORMError
  AbstractSpakkySqlAlchemyError --> AbstractSpakkySqlAlchemyPersistencyError
  AbstractSpakkySqlAlchemyPersistencyError --> AgentPersistenceRowNotFoundError
  AbstractSpakkyGrpcError --> AbstractGrpcStatusError
  AbstractSpakkyActuatorError --> CannotEvaluateAsyncExtensionSynchronouslyError
  AbstractSpakkyOidcError --> OidcDiscoveryError
  AbstractSpakkyOidcError --> OidcJwksError
  AbstractSpakkyOidcError --> OidcCredentialError
  AbstractSpakkyOidcError --> OidcTokenValidationError
  AbstractOpenFgaError --> OpenFgaProviderUnavailableError
  AbstractOpenFgaError --> OpenFgaReferenceMappingError
  AbstractVllmError --> VllmTransportError
  AbstractVllmError --> VllmTimeoutError
  AbstractVllmError --> VllmResponseError
  AbstractVllmError --> VllmConstrainedDecodingUnsupportedError
  AbstractVllmError --> VllmStreamingDisabledError
  AbstractVllmError --> VllmModelRefusalError
  AbstractVllmError --> VllmStreamingNotImplementedError
  PolicyDocumentError --> PolicyDocumentLoadError
  PolicyDocumentError --> PolicyDocumentValidationError
  PolicyDocumentError --> PolicyEvaluationError

기반 에러 클래스

AbstractSpakkyFrameworkError

모든 Spakky 프레임워크 에러의 최상위 기반 클래스입니다.

from spakky.core.common.error import AbstractSpakkyFrameworkError

class AbstractSpakkyFrameworkError(Exception, ABC):
    """모든 Spakky 프레임워크 에러의 기반 클래스"""

    message: ClassVar[str]  # 에러 메시지 (클래스 수준 또는 인스턴스 수준)

특징:

  • message 속성으로 사람이 읽을 수 있는 에러 메시지 제공
  • 클래스 수준 기본 메시지 또는 인스턴스별 커스텀 메시지 지원

코어 패키지 에러

spakky (코어)

AbstractSpakkyApplicationError

애플리케이션 부트스트랩 관련 에러입니다.

from spakky.core.application.error import AbstractSpakkyApplicationError
from spakky.core.application.startup_diagnostics import (
    StartupElapsedTimeCannotBeNegativeError,
    StartupFailureSummaryNotAllowedError,
    StartupFailureSummaryRequiredError,
    StartupProcessedCountCannotBeNegativeError,
)
에러 설명
CannotDetermineScanPathError 스캔 경로를 자동 결정할 수 없음
CannotAssignSystemContextIDError 시스템 컨텍스트 ID 덮어쓰기 시도
ApplicationContextAlreadyStartedError 이미 시작된 컨텍스트를 재시작 시도
ApplicationContextAlreadyStoppedError 이미 중지된 컨텍스트를 재중지 시도
EventLoopThreadNotStartedInApplicationContextError 이벤트 루프 스레드 미시작 상태에서 접근
EventLoopThreadAlreadyStartedInApplicationContextError 이벤트 루프 스레드 중복 시작 시도
StartupElapsedTimeCannotBeNegativeError startup phase elapsed time이 음수
StartupProcessedCountCannotBeNegativeError startup phase processed count가 음수
StartupFailureSummaryRequiredError 실패 phase record에 failure summary가 없음
StartupFailureSummaryNotAllowedError 성공 phase record에 failure summary가 있음

AbstractSpakkyPodError

Pod 등록 및 인스턴스화 관련 에러입니다.

from spakky.core.pod.error import AbstractSpakkyPodError
from spakky.core.pod.annotations.pod import UnsupportedCollectionDependencyTypeError
에러 설명
PodAnnotationFailedError Pod 어노테이션 처리 실패
PodInstantiationFailedError Pod 인스턴스 생성 실패
NegativeOrderValueError 음수 @Order 값 지정
QualifierSelectorNotCallableError @Qualifier selector가 호출 불가
CannotDeterminePodTypeError Pod 타입 추론 불가
CannotUseVarArgsInPodError *args/**kwargs 사용 금지
CannotUsePositionalOnlyArgsInPodError 위치 전용 인자 사용 금지
CannotUseOptionalReturnTypeInPodError Optional 반환 타입 금지 (함수 Pod)
UnsupportedCollectionDependencyTypeError 지원하지 않는 collection 의존성 타입
UnexpectedDependencyNameInjectedError 예상치 못한 이름의 의존성 주입
UnexpectedDependencyTypeInjectedError 예상치 못한 타입의 의존성 주입

컨테이너 에러

from spakky.core.pod.interfaces.container import (
    CircularDependencyGraphDetectedError,
    NoSuchPodError,
    NoSuchPodBindingTargetError,
    NoUniquePodError,
    InvalidPodBindingError,
    PodBindingNotSupportedError,
    CannotRegisterNonPodObjectError,
    PodNameAlreadyExistsError,
)
에러 설명
CircularDependencyGraphDetectedError 순환 의존성 감지
NoSuchPodError 요청한 Pod를 찾을 수 없음
NoSuchPodBindingTargetError 명시 binding 대상 없음
NoUniquePodError 여러 후보 Pod 중 선택 불가
InvalidPodBindingError 잘못된 binding policy
PodBindingNotSupportedError 컨테이너가 binding 미지원
CannotRegisterNonPodObjectError @Pod 없는 객체 등록 시도
PodNameAlreadyExistsError Pod 이름 중복

공통 유틸리티 에러

from spakky.core.common.annotation import AnnotationNotFoundError, MultipleAnnotationFoundError
from spakky.core.common.error import GenericMROTypeError
from spakky.core.common.importing import CannotScanNonPackageModuleError
from spakky.core.common.metadata import InvalidAnnotatedTypeError, MetadataNotFoundError
에러 설명
GenericMROTypeError generic_mro()에 타입이 아닌 값 전달
CannotScanNonPackageModuleError 패키지가 아닌 모듈을 스캔 대상으로 지정
AnnotationNotFoundError 요청한 어노테이션 메타데이터 없음
MultipleAnnotationFoundError 동일 어노테이션이 여러 개 발견됨
MetadataNotFoundError Annotated 타입에서 기대 메타데이터 없음
InvalidAnnotatedTypeError 유효하지 않은 Annotated 타입 전달

AbstractSpakkyAOPError

AOP 관련 에러입니다.

from spakky.core.aop.error import AbstractSpakkyAOPError
에러 설명
AspectInheritanceError Aspect가 IAspect/IAsyncAspect 미구현

spakky-domain

도메인 모델 관련 에러입니다.

from spakky.domain.error import (
    AbstractSpakkyDomainError,
    AbstractDomainValidationError,
)
에러 설명
AbstractSpakkyDomainError 도메인 에러 기반 클래스
AbstractDomainValidationError 도메인 검증 에러 기반 클래스
CannotMonkeyPatchEntityError Entity 속성 직접 변경 시도
UnhashableFieldTypeError ValueObject 필드 타입이 해시 불가

spakky-auth

인증/인가 semantic model, provider capability validation, snapshot propagation 관련 에러입니다.

from spakky.auth.error import (
    AbstractSpakkyAuthError,
    AuthContextError,
    AuthContextNotFoundError,
    InvalidAuthContextValueError,
    CredentialCarrierError,
    AuthenticationError,
    AuthorizationError,
    ConflictingAuthMetadataError,
    AuthRequirementDeniedError,
    AuthRequirementProviderUnavailableError,
    AuthContextSnapshotError,
    MissingAuthContextSnapshotError,
    InvalidAuthContextSnapshotError,
    ExpiredAuthContextSnapshotError,
    AuthVerificationProviderUnavailableError,
)
from spakky.auth.startup import (
    AuthStartupCapabilityValidationError,
    AuthStartupContainerUnavailableError,
)
에러 설명
AbstractSpakkyAuthError auth 에러 기반 클래스
AuthContextError AuthContext 저장 또는 조회 실패 기반 클래스
AuthContextNotFoundError ApplicationContextAuthContext 값이 없음
InvalidAuthContextValueError context 값이 AuthContext 인스턴스가 아님
CredentialCarrierError credential carrier를 해석할 수 없음
AuthenticationError 인증 실패
AuthorizationError 인가 실패 기반 클래스
ConflictingAuthMetadataError public marker와 protected requirement가 함께 유효함
AuthRequirementDeniedError requirement decision이 ALLOW가 아니며 decision을 보존함
AuthRequirementProviderUnavailableError 보호 requirement를 처리할 provider가 없음
AuthContextSnapshotError snapshot 전파/검증 실패 기반 클래스
MissingAuthContextSnapshotError snapshot metadata가 없음
InvalidAuthContextSnapshotError snapshot envelope가 malformed 또는 unsigned 상태
ExpiredAuthContextSnapshotError snapshot 유효 시간이 만료됨
AuthVerificationProviderUnavailableError snapshot verifier provider를 사용할 수 없음
AuthStartupCapabilityValidationError 필요한 auth capability provider 수가 0개 또는 2개 이상
AuthStartupContainerUnavailableError startup validation에 필요한 container가 없음

spakky-event

이벤트 시스템 관련 에러입니다.

from spakky.event.error import (
    AbstractSpakkyEventError,
    AuthSnapshotPropagationContextUnavailableError,
    AuthSnapshotPropagationSignerUnavailableError,
    InvalidMessageError,
    UnknownEventTypeError,
)
에러 설명
AuthSnapshotPropagationContextUnavailableError snapshot 전파가 활성화되었지만 ApplicationContext를 읽을 수 없음
AuthSnapshotPropagationSignerUnavailableError snapshot 전파가 활성화되었지만 signer provider가 없음
InvalidMessageError 잘못된 메시지 형식
UnknownEventTypeError Domain/Integration Event가 아닌 타입 발행

spakky-data

데이터 접근 관련 에러입니다.

from spakky.data.persistency.error import AbstractSpakkyPersistencyError
from spakky.data.persistency.repository import EntityNotFoundError, VersionConflictError
from spakky.data.external.error import AbstractSpakkyExternalError
에러 설명 상속
AbstractSpakkyPersistencyError 영속성 에러 기반 클래스 AbstractSpakkyFrameworkError
EntityNotFoundError 엔티티 조회 실패 AbstractSpakkyDomainError
VersionConflictError 낙관적 락 충돌 AbstractSpakkyDomainError
AbstractSpakkyExternalError 외부 서비스 에러 기반 클래스 AbstractSpakkyFrameworkError

spakky-task

태스크 시스템 관련 에러입니다.

from spakky.task.error import (
    AbstractSpakkyTaskError,
    TaskNotFoundError,
    TaskApplicationContextNotFoundError,
    TaskAsyncInvocationRequiredError,
    DuplicateTaskError,
    InvalidScheduleSpecificationError,
)
에러 설명
TaskNotFoundError 레지스트리에서 태스크를 찾을 수 없음
TaskApplicationContextNotFoundError 직접 실행에 필요한 ApplicationContext가 없음
TaskAsyncInvocationRequiredError async task를 sync 직접 실행 경로로 호출함
DuplicateTaskError 중복 태스크 등록 시도
InvalidScheduleSpecificationError @scheduleinterval/at/crontab 중 하나만 필요

spakky-actuator

Actuator health/info extension 평가 관련 에러입니다.

from spakky.actuator.error import (
    AbstractSpakkyActuatorError,
    CannotEvaluateAsyncExtensionSynchronouslyError,
)
에러 설명
AbstractSpakkyActuatorError actuator 에러 기반 클래스
CannotEvaluateAsyncExtensionSynchronouslyError sync 평가 경로에서 async-only extension을 평가하려 함

spakky-cache

애플리케이션 데이터 캐시 관련 에러입니다.

from spakky.cache.error import (
    AbstractSpakkyCacheError,
    CacheBackendCapabilityError,
    CacheKeyGenerationError,
    InvalidCacheTTLError,
)
에러 설명
InvalidCacheTTLError 0 이하 TTL 값 지정 시도
CacheKeyGenerationError cache 어노테이션 key 생성 실패
CacheBackendCapabilityError cache annotation이 backend 미지원 capability를 요구

spakky-tracing

분산 트레이싱 관련 에러입니다.

from spakky.tracing.error import (
    AbstractSpakkyTracingError,
    InvalidTraceparentError,
)
에러 설명
InvalidTraceparentError traceparent 헤더 형식이 유효하지 않음

spakky-agent

Agentic workflow contract 관련 에러입니다.

from spakky.agent.error import (
    AbstractSpakkyAgentError,
    AgentDefinitionError,
    AgentToolBindingError,
    AgentBootstrapError,
    AgentPersistenceConfigurationError,
    AgentModelConfigurationError,
    AgentOutputGuardError,
)
에러 설명 상속
AbstractSpakkyAgentError agent 에러 기반 클래스 AbstractSpakkyFrameworkError
AgentDefinitionError @Agent/@agent_tool 정의 계약 오류 AbstractSpakkyAgentError
AgentToolBindingError model tool-call payload를 Python signature에 bind할 수 없음 AbstractSpakkyAgentError
AgentBootstrapError agent bootstrap 검증 실패 AbstractSpakkyAgentError
AgentPersistenceConfigurationError durable agent persistence contribution 누락 AgentBootstrapError
AgentModelConfigurationError 필요한 model adapter 등록 누락 AgentBootstrapError
AgentOutputGuardError streaming output guard가 unsafe exposure를 감지 AbstractSpakkyAgentError

AgentToolBindingError는 tool callable 실행 전에 발생하므로, schema에 없는 인자·필수 인자 누락·positional/keyword 중복 같은 잘못된 model payload가 side effect를 만들기 전에 차단됩니다.


플러그인 에러

spakky-fastapi

FastAPI 통합 관련 에러입니다. HTTP 상태 코드와 JSON 응답 변환을 지원합니다.

from spakky.plugins.fastapi.error import (
    AbstractSpakkyFastAPIError,
    BadRequest,
    Unauthorized,
    Forbidden,
    NotFound,
    Conflict,
    InternalServerError,
)
에러 HTTP 상태 설명
BadRequest 400 잘못된 요청
Unauthorized 401 인증 필요
Forbidden 403 접근 권한 없음
NotFound 404 리소스 없음
Conflict 409 리소스 충돌
InternalServerError 500 내부 서버 에러

JSON 응답 변환:

from spakky.plugins.fastapi.error import NotFound

try:
    user = await repository.find_by_id(user_id)
    if user is None:
        raise NotFound()
except NotFound as e:
    return e.to_response(show_traceback=False)

응답 예시:

{
    "message": "Not Found",
    "args": [],
    "traceback": null
}

spakky-sqlalchemy

SQLAlchemy 통합 관련 에러입니다.

from spakky.plugins.sqlalchemy.error import AbstractSpakkySqlAlchemyError
from spakky.plugins.sqlalchemy.orm.error import AbstractSpakkySqlAlchemyORMError
from spakky.plugins.sqlalchemy.persistency.error import AbstractSpakkySqlAlchemyPersistencyError
from spakky.plugins.sqlalchemy.agent.error import AgentPersistenceRowNotFoundError
에러 설명 상속
AbstractSpakkySqlAlchemyError SQLAlchemy 에러 기반 클래스 AbstractSpakkyFrameworkError
AbstractSpakkySqlAlchemyORMError ORM 에러 기반 클래스 AbstractSpakkySqlAlchemyError
AbstractSpakkySqlAlchemyPersistencyError 영속성 에러 기반 클래스 AbstractSpakkySqlAlchemyError
CannotUseTableAnnotationError @Table 데코레이터 사용 오류 AbstractSpakkySqlAlchemyORMError
TargetDomainNotSpecifiedError @Table에 도메인 타입 미지정 AbstractSpakkySqlAlchemyORMError
NoSchemaFoundFromDomainError 도메인 타입에 대한 스키마 없음 AbstractSpakkySqlAlchemyORMError
CannotDetermineAggregateTypeError Aggregate 타입 추론 불가 AbstractSpakkySqlAlchemyPersistencyError
SessionNotInitializedError 세션 미초기화 상태에서 접근 AbstractSpakkySqlAlchemyPersistencyError
AgentPersistenceRowNotFoundError agent persistence row를 찾을 수 없음 AbstractSpakkySqlAlchemyPersistencyError

spakky-celery

Celery 통합 관련 에러입니다.

from spakky.plugins.celery.error import (
    AbstractSpakkyCeleryError,
    InvalidTimezoneError,
    InvalidScheduleRouteError,
)
에러 설명
AbstractSpakkyCeleryError Celery 에러 기반 클래스
InvalidTimezoneError 유효하지 않은 IANA timezone 문자열
InvalidScheduleRouteError ScheduleRoute에 유효한 스케줄 명세가 없음

spakky-cryptography

암호화와 패스워드 해싱 관련 에러입니다. spakky-cryptography 에러들은 패키지별 기반 클래스 없이 AbstractSpakkyFrameworkError를 직접 상속합니다.

from spakky.plugins.cryptography.error import (
    DecryptionFailedError,
    KeySizeError,
    PrivateKeyRequiredError,
    CannotImportAsymmetricKeyError,
    InvalidKeyConstructorCallError,
    IncompatibleKeyTypeError,
    PasswordRequiredError,
    AsymmetricKeyRequiredError,
)
에러 설명
DecryptionFailedError 복호화 실패 (키 오류 또는 데이터 손상)
KeySizeError 유효하지 않은 암호화 키 크기
PrivateKeyRequiredError 비대칭 키 연산 시 개인키 미제공
CannotImportAsymmetricKeyError 비대칭 키 임포트 실패
InvalidKeyConstructorCallError Key() 생성자 호출 인자 오류
IncompatibleKeyTypeError 호환되지 않는 키 타입 비교
PasswordRequiredError 필수 password 파라미터 누락
AsymmetricKeyRequiredError 비대칭 키 또는 크기 파라미터 누락

spakky-oidc

OIDC bearer authentication provider 관련 에러입니다. Provider는 이 에러들을 인증 실패 decision으로 매핑하거나 adapter 경계에서 fail-closed 응답으로 변환합니다.

from spakky.plugins.oidc.error import (
    AbstractSpakkyOidcError,
    OidcCredentialError,
    OidcDiscoveryError,
    OidcJwksError,
    OidcTokenValidationError,
)
에러 설명
AbstractSpakkyOidcError OIDC provider 에러 기반 클래스
OidcDiscoveryError discovery metadata를 로드하거나 신뢰할 수 없음
OidcJwksError JWKS key material이 없거나 bearer credential 검증에 실패
OidcCredentialError credential carrier가 bearer token으로 사용할 수 없음
OidcTokenValidationError JWT signature, issuer, audience, 시간 claim 등 OIDC 검증 실패

spakky-policy

Policy document loader/evaluator 내부의 provider-local 입력 검증 예외입니다. 이 예외들은 AbstractSpakkyFrameworkError를 상속하지 않는 plain Exception 계층이며, auth provider 경계에서는 AuthorizationDecision.ERROR로 매핑됩니다.

from spakky.plugins.policy.error import (
    PolicyDocumentError,
    PolicyDocumentLoadError,
    PolicyDocumentValidationError,
    PolicyEvaluationError,
)
에러 설명
PolicyDocumentError policy document 실패 기반 클래스
PolicyDocumentLoadError policy document를 로드할 수 없음
PolicyDocumentValidationError 입력 문서를 canonical policy model로 만들 수 없음
PolicyEvaluationError policy 평가를 완료할 수 없음

spakky-outbox

Transactional Outbox 관련 에러입니다.

from spakky.outbox.error import AbstractSpakkyOutboxError
에러 설명
AbstractSpakkyOutboxError Outbox 에러 기반 클래스

spakky-opentelemetry

OpenTelemetry 통합 관련 에러입니다.

from spakky.plugins.opentelemetry.error import (
    AbstractSpakkyOpenTelemetryError,
    UnsupportedExporterTypeError,
)
에러 설명
AbstractSpakkyOpenTelemetryError OpenTelemetry 에러 기반 클래스
UnsupportedExporterTypeError 지원하지 않는 exporter 타입 설정 시 발생

spakky-logging

구조화 로깅 관련 에러입니다.

from spakky.plugins.logging.error import (
    AbstractSpakkyLoggingError,
    UnknownLogFormatError,
)
에러 설명
AbstractSpakkyLoggingError 로깅 에러 기반 클래스
UnknownLogFormatError 인식할 수 없는 로그 포맷

spakky-redis

Redis 캐시 백엔드 관련 에러입니다.

from spakky.plugins.redis.error import (
    AbstractSpakkyRedisError,
    RedisCacheLockTimeoutError,
    RedisCacheOperationError,
    RedisCacheSerializationError,
)
에러 설명
AbstractSpakkyRedisError Redis 캐시 백엔드 에러 기반 클래스
RedisCacheOperationError Redis 명령 실행 또는 응답 변환 실패
RedisCacheSerializationError cache 값 직렬화 또는 역직렬화 실패
RedisCacheLockTimeoutError cache population lock 획득 타임아웃

spakky-saga

사가 오케스트레이션 관련 에러입니다.

from spakky.saga.error import (
    AbstractSpakkySagaError,
    SagaFlowDefinitionError,
    SagaCompensationFailedError,
    SagaStepTimeoutError,
    SagaParallelMergeConflictError,
    SagaEngineNotConnectedError,
)
에러 설명
AbstractSpakkySagaError 사가 에러 기반 클래스
SagaFlowDefinitionError SagaFlow 정의 오류 (잘못된 흐름 구성)
SagaCompensationFailedError 보상 로직 실행 중 예외 발생
SagaStepTimeoutError step 타임아웃 초과 (엔진 내부, on_error 전략으로 라우팅)
SagaParallelMergeConflictError 병렬 단계 결과 병합 시 충돌
SagaEngineNotConnectedError 사가 엔진이 초기화되지 않은 상태에서 실행 시도

spakky-grpc

gRPC 통합 관련 에러입니다. gRPC 상태 코드 매핑 에러와 스키마 에러로 나뉩니다.

from spakky.plugins.grpc.error import (
    AbstractSpakkyGrpcError,
    AbstractGrpcStatusError,
    InvalidArgument,
    NotFound,
    AlreadyExists,
    PermissionDenied,
    Unauthenticated,
    FailedPrecondition,
    Unavailable,
    InternalError,
    UnsupportedFieldTypeError,
    MissingProtoFieldAnnotationError,
    UnsupportedResponseTypeError,
    DescriptorAlreadyRegisteredError,
)

gRPC 상태 코드 에러:

에러 gRPC 상태 코드 설명
AbstractGrpcStatusError gRPC status error의 공통 기반 클래스
InvalidArgument INVALID_ARGUMENT 잘못된 요청 인자
NotFound NOT_FOUND 리소스 없음
AlreadyExists ALREADY_EXISTS 리소스 이미 존재
PermissionDenied PERMISSION_DENIED 권한 없음
Unauthenticated UNAUTHENTICATED 인증 필요
FailedPrecondition FAILED_PRECONDITION 사전 조건 미충족
Unavailable UNAVAILABLE 서비스 이용 불가
InternalError INTERNAL 내부 서버 에러

스키마 에러:

에러 설명
UnsupportedFieldTypeError 지원하지 않는 protobuf 필드 타입
MissingProtoFieldAnnotationError ProtoField 어노테이션 누락
UnsupportedResponseTypeError protobuf Message나 Pydantic BaseModel이 아닌 응답
DescriptorAlreadyRegisteredError 이미 등록된 descriptor 재등록 시도

spakky-openfga

OpenFGA 관계 검사 provider 관련 에러입니다. provider 내부에서는 이 에러들을 AuthorizationDecision으로 매핑하므로 enforcement 경계는 fail-closed decision을 처리합니다.

from spakky.plugins.openfga.error import (
    AbstractOpenFgaError,
    OpenFgaProviderUnavailableError,
    OpenFgaReferenceMappingError,
)
에러 설명
AbstractOpenFgaError OpenFGA provider 에러의 공통 기반 클래스
OpenFgaProviderUnavailableError OpenFGA check provider 호출 실패 또는 비가용 상태
OpenFgaReferenceMappingError canonical auth ref를 OpenFGA user/object/relation으로 변환할 수 없음

spakky-vllm

vLLM OpenAI-compatible model adapter 관련 에러입니다. Provider 응답은 spakky-agentModelError/stream event로 변환되기 전에 이 계층에서 정규화됩니다.

from spakky.plugins.vllm.error import (
    AbstractVllmError,
    VllmConstrainedDecodingUnsupportedError,
    VllmModelRefusalError,
    VllmResponseError,
    VllmStreamingDisabledError,
    VllmStreamingNotImplementedError,
    VllmTimeoutError,
    VllmTransportError,
)
에러 설명
AbstractVllmError vLLM adapter 에러 기반 클래스
VllmTransportError OpenAI-compatible endpoint 요청 실패
VllmTimeoutError vLLM 요청 타임아웃
VllmResponseError provider 응답을 Spakky model contract로 매핑할 수 없음
VllmConstrainedDecodingUnsupportedError 요청된 tool constraint를 vLLM이 강제할 수 없음
VllmStreamingDisabledError plugin 설정에서 streaming이 비활성화됨
VllmModelRefusalError 모델이 정상 completion 생성을 거부함
VllmStreamingNotImplementedError pre-streaming adapter 실패 호환 alias

커스텀 에러 정의

도메인 에러

from spakky.domain.error import AbstractDomainValidationError

class InvalidEmailError(AbstractDomainValidationError):
    """잘못된 이메일 형식"""
    message = "Invalid email format"

class InsufficientBalanceError(AbstractDomainValidationError):
    """잔액 부족"""
    message = "Insufficient balance for this operation"

애플리케이션 에러

from spakky.core.application.error import AbstractSpakkyApplicationError

class ConfigurationError(AbstractSpakkyApplicationError):
    """설정 오류"""
    message = "Invalid configuration"

HTTP 에러 (FastAPI)

from spakky.plugins.fastapi.error import AbstractSpakkyFastAPIError
from typing import ClassVar
from fastapi import status

class TooManyRequestsError(AbstractSpakkyFastAPIError):
    """요청 제한 초과"""
    message = "Too many requests"
    status_code: ClassVar[int] = status.HTTP_429_TOO_MANY_REQUESTS

에러 처리 패턴

try-except로 특정 에러 처리

from spakky.core.pod.interfaces.container import NoSuchPodError, NoUniquePodError

try:
    service = context.get(IUserService)
except NoSuchPodError:
    logger.error("UserService not registered")
    raise
except NoUniquePodError:
    logger.error("Multiple UserService candidates")
    raise

에러 계층으로 그룹 처리

from spakky.domain.error import AbstractDomainValidationError

try:
    user = User.create(command)
except AbstractDomainValidationError as e:
    # 모든 도메인 검증 에러를 한번에 처리
    return {"error": e.message}

FastAPI 에러 핸들러

from fastapi import FastAPI
from spakky.plugins.fastapi.error import AbstractSpakkyFastAPIError

app = FastAPI()

@app.exception_handler(AbstractSpakkyFastAPIError)
async def handle_spakky_error(request, exc: AbstractSpakkyFastAPIError):
    return exc.to_response(show_traceback=app.debug)

모범 사례

1. 적절한 기반 클래스 선택

# 도메인 로직 에러 → AbstractDomainValidationError
class InvalidOrderStateError(AbstractDomainValidationError):
    message = "Cannot cancel a shipped order"

# HTTP 응답 에러 → AbstractSpakkyFastAPIError
class OrderNotFoundError(NotFound):
    message = "Order not found"

2. 상세 메시지 제공

class CircularDependencyGraphDetectedError(AbstractSpakkyPodError):
    message = "Circular dependency graph detected"

    def __init__(self, dependency_chain: list[type]) -> None:
        super().__init__()
        self.dependency_chain = dependency_chain

    @property
    def dependency_path(self) -> str:
        return " -> ".join(t.__name__ for t in self.dependency_chain)

3. 에러 체이닝

try:
    result = external_service.call()
except ExternalError as e:
    raise ApplicationError("External service failed") from e

4. 로깅과 함께 사용

import logging

logger = logging.getLogger(__name__)

try:
    pod = context.get(IService)
except NoSuchPodError as e:
    logger.error(f"Service not found: {e}", exc_info=True)
    raise

에러 테스트

import pytest
from spakky.domain.error import AbstractDomainValidationError

class InvalidEmailError(AbstractDomainValidationError):
    message = "Invalid email"

def test_invalid_email_error():
    with pytest.raises(InvalidEmailError) as exc_info:
        raise InvalidEmailError()

    assert exc_info.value.message == "Invalid email"
    assert isinstance(exc_info.value, AbstractDomainValidationError)

def test_error_hierarchy():
    error = InvalidEmailError()

    # 계층 확인
    assert isinstance(error, AbstractDomainValidationError)
    assert isinstance(error, Exception)