rfgen.core.errors

The exception hierarchy for the framework. Every error rfgen raises is a subclass of RfgenError, which lets callers catch all framework faults with a single except clause while still discriminating on more specific subclasses when handling retries, validation, or plugin-lookup failures.

Every subclass carries a structured context: dict[str, object] attribute that downstream telemetry can read. The values are JSON-serializable so log sinks can emit them as-is. str(err) returns the top-level message; the full context is available via err.context.

Module summary

from rfgen.core.errors import (
    RfgenError,
    ConfigError,
    PluginNotFoundError,
    BackendUnavailableError,
    StorageError,
)

try:
    pipeline.run(cfg)
except BackendUnavailableError as exc:
    raise SystemExit(f"missing optional dep: {exc}")
except PluginNotFoundError as exc:
    raise SystemExit(f"missing plugin: {exc}")
except ConfigError as exc:
    raise SystemExit(f"invalid config: {exc}")
except RfgenError as exc:
    log.exception("rfgen pipeline failed: %s", exc)
    raise

The hierarchy is one level deep apart from RegistryError’s two specializations. Two subclasses (BackendUnavailableError, InferenceError) carry extra structured fields beyond the base context attribute.

Class index

Class

Parent

Notes

RfgenError

Exception

Root exception; carries context: dict[str, object]

ConfigError

RfgenError

Hydra/Pydantic config failed validation or composition

ValidationError

RfgenError

Runtime validation contract violated

RegistryError

RfgenError

Plugin registry encountered a structural problem (e.g., duplicate registration)

PluginNotFoundError

RegistryError

Registry lookup miss; message lists available names

PluginVersionError

RegistryError

Plugin’s declared version is incompatible with the framework

EmitterError

RfgenError

Emitter-layer synthesis failure

ChannelError

RfgenError

Channel-layer impairment-application failure

SceneError

RfgenError

Scene composer cannot complete composition

LabelError

RfgenError

Labeler failed to derive labels

AnnotationError

RfgenError

Annotator failed to produce text

StorageError

RfgenError

Storage backend persistence failure

IOError

RfgenError

rfgen-side I/O path failure (downloads, fixture loads, manifests). Shadows the built-in IOError

DeterminismError

RfgenError

Determinism invariant violated at runtime

BackendUnavailableError

RfgenError

An optional rfgen[<extra>] dep was required but not installed

InferenceError

RfgenError

Inference-backend response failed JSON-shape or empty-response validation

PlacementError

RfgenError

Placement strategy could not satisfy its constraints

The shipped class set lives at src/rfgen/core/errors.py and is exported via rfgen.core.errors.__all__. Adding or removing a subclass is a breaking change for any caller that catches by specific type.


class rfgen.core.errors.RfgenError(Exception)

Root of the rfgen exception hierarchy. Every framework-raised exception subclasses this.

class RfgenError(Exception):
    def __init__(
        self,
        message: str = "",
        *,
        context: dict[str, Any] | None = None,
    ) -> None: ...

Attributes

Attribute

Type

Purpose

context

dict[str, Any]

Structured key/value attachments. JSON-serializable so log sinks can emit them as-is. Defaults to {} when no context kwarg is passed

Notes

  • Subclasses inherit __init__ unchanged unless they override it. BackendUnavailableError and InferenceError are the only two that override.

  • Every public callable in the framework (any callable exported via a module’s __all__) lists in its docstring Raises: section the exact RfgenError subclasses it can raise. A contract test in validation-and-audit walks every public callable, parses the docstring with docstring_parser>=0.16 (Google style), AST-walks the implementation source for raise <Name>(...) nodes, and asserts the AST set equals the docstring set. Standard-library exceptions raised by callees are not in scope.


class rfgen.core.errors.ConfigError(RfgenError)

Raised when a Hydra/Pydantic config fails validation or composition.

The canonical entry point that surfaces this is validate_config (in rfgen.config), which catches pydantic.ValidationError and re-raises as ConfigError(message=str(exc), context={"errors": json.loads(exc.json())}) from exc. from_hydra raises ConfigError directly for non-config / non-dict / ListConfig inputs (with a Hydra-specific message). See Reference / API / Config for both.

ConfigError.context["errors"] is a JSON-serializable list of Pydantic error entries. Coercion is delegated to Pydantic’s ValidationError.json() so non-serializable ctx values (e.g., raw ValueError instances raised inside custom @model_validators) become string-serialized in a single step.


class rfgen.core.errors.ValidationError(RfgenError)

Raised when a runtime validation contract is violated. Distinct from ConfigError, which is reserved for config-time failures.


class rfgen.core.errors.RegistryError(RfgenError)

Raised when the plugin registry encounters a structural problem (e.g., duplicate registration under the same name). The message names both the existing source module and the incoming source module so the conflict is debuggable.

The two specializations under RegistryError are PluginNotFoundError (lookup miss) and PluginVersionError (version incompatibility).

class rfgen.core.errors.PluginNotFoundError(RegistryError)

Raised when a registry is asked for a plugin name that is not registered. The message lists the available names for that registry’s group.

class rfgen.core.errors.PluginVersionError(RegistryError)

Raised when a plugin’s declared version (parsed via packaging.version.Version) is incompatible with the framework’s pinned range.


class rfgen.core.errors.EmitterError(RfgenError)

Raised for emitter synthesis failures. Examples: a backend SDK returned an unexpected shape, a pre-recorded capture failed checksum, or a parameter combination is out of the documented support region.

class rfgen.core.errors.ChannelError(RfgenError)

Raised for channel and impairment-application failures. Examples: a Sionna RT scene fails to converge, a polyphase resampler hits a non-rational rate ratio, or an RX frontend backend rejects an out-of-band parameter.

class rfgen.core.errors.SceneError(RfgenError)

Raised when scene composition cannot complete. Examples: density constraints unsatisfiable, placement budget exhausted, or an RT geometry blob is missing.

class rfgen.core.errors.LabelError(RfgenError)

Raised when label derivation fails. Examples: a bbox cannot be derived from a malformed Signal, or a segmentation mask shape mismatches the IQ tensor.

class rfgen.core.errors.AnnotationError(RfgenError)

Raised when annotation generation fails. Distinct from InferenceError, which targets inference-backend response-validation failures specifically.

class rfgen.core.errors.StorageError(RfgenError)

Raised by storage backends for persistence failures. Examples: bucket access denied, schema mismatch on read, or atomic-shard commit failure.

class rfgen.core.errors.IOError(RfgenError)

Raised by rfgen-side I/O paths: dataset downloads, fixture loads, manifest reads, etc.

This class shadows the built-in IOError. Code that needs the built-in should import it explicitly as import builtins; builtins.IOError. The acceptance contract for the errors module enumerates IOError as a required RfgenError subclass; the override is intentional, not an accident.

class rfgen.core.errors.DeterminismError(RfgenError)

Raised when a determinism invariant is violated at runtime. Examples: a contract test that re-runs seed_for(...) and observes a different output, a backend that bypassed derive_rng and pulled from global RNG state.

class rfgen.core.errors.PlacementError(RfgenError)

Raised by placement strategies when they cannot satisfy their constraints (for example, requested density too high for the available band or no admissible time slots).


class rfgen.core.errors.BackendUnavailableError(RfgenError)

Raised when an optional rfgen[<extra>] dependency is required but not installed. Carries missing_import, extra, and (optionally) class_name as both keyword-only constructor args and as inherited attributes.

class BackendUnavailableError(RfgenError):
    def __init__(
        self,
        *,
        missing_import: str,
        extra: str,
        class_name: str | None = None,
        message: str | None = None,
        context: dict[str, Any] | None = None,
    ) -> None: ...

    missing_import: str
    extra: str
    class_name: str | None

Behavior

  • Default messages retain their literal legacy pip install rfgen[{extra}] hint. It is not a supported source-checkout instruction: from the checkout root, install the missing dependency with uv pip install -e '.[<extra>]'; for a release wheel, reinstall that wheel with the matching extra.

  • class_name selects the class-specific wording ("{class_name} requires the '{extra}' extra") rather than the missing-import wording. Custom raise sites may supply a source- or wheel-scoped message override when that gives a more direct recovery action.

  • context automatically merges {"missing_import": <name>, "extra": <name>} (plus "class_name" when supplied) with any caller-supplied additional keys.


class rfgen.core.errors.InferenceError(RfgenError)

Raised when an inference-backend response fails validation. The class wraps any inference backend (text, vision-language, audio-language); the name was generalized from the earlier LLMResponseError so the protocol stays modality-agnostic. Carries template_id, run_id, and failure_summary as both keyword-only constructor args and as inherited attributes.

class InferenceError(RfgenError):
    def __init__(
        self,
        *,
        template_id: str,
        run_id: str,
        failure_summary: str,
        message: str | None = None,
        context: dict[str, Any] | None = None,
    ) -> None: ...

    template_id: str
    run_id: str
    failure_summary: str

Behavior

  • Default message: f"Inference response failed validation: {failure_summary}".

  • context automatically merges {"template_id": ..., "run_id": ..., "failure_summary": ...} with any caller-supplied additional keys.

  • Failure modes (failure_summary values) typically fall into two documented buckets: schema mismatch (the response did not match the prompt’s json_schema) or empty response (the backend returned no usable content). Free-form vocabulary and semantic quality are not deterministic inference failures.


See Also


Legacy class names

The anchors below preserve compatibility links for historical error names. The current error hierarchy is defined by the class index above.

Legacy: ConfigurationError

Renamed to ConfigError in the shipped rfgen.core.errors module.

Legacy: UnsupportedConfiguration

Removed from the shipped surface. Plugin code that cannot satisfy a requested config combination raises ConfigError (config-time) or ValidationError (runtime).

Legacy: GenerationError

Removed from the shipped surface. The shipped hierarchy exposes per-layer typed errors directly: EmitterError, ChannelError, SceneError. Catch RfgenError for an umbrella.

Legacy: LabelComputeError

Collapsed into LabelError in the shipped surface. The structured context carries the failure-mode discriminator the legacy subclass used to encode by type.

Legacy: LabelInconsistencyError

Collapsed into LabelError in the shipped surface. context["reason"] distinguishes the inconsistency mode (bbox / segmentation / metadata disagreement).

Legacy: LLMError

Collapsed into InferenceError. Network and transport failures surface via the underlying SDK exception; rfgen wraps response-validation failures only.

Legacy: LLMRateLimitError

Removed from the public surface. Rate-limit handling is the responsibility of the inference client wrapper (rfgen.inference), which surfaces SDK-native rate-limit exceptions or wraps them in InferenceError with failure_summary="rate_limited".

Legacy: LLMRefusalError

Collapsed into InferenceError in the shipped surface, with failure_summary="refused" in the structured context.

Legacy: HallucinationError

Collapsed into InferenceError in the shipped surface, with failure_summary="hallucination" and the verifier-rejected text in context["rejected_text"].

Legacy: LLMResponseError

Renamed to InferenceError in the shipped surface. The class wraps any inference backend (text, vision-language, audio-language), so the name was generalized.

Legacy: StorageTransientError

Collapsed into StorageError in the shipped surface. Retryable failures are distinguished by context["retryable"] = True; the storage backend wraps the underlying SDK exception in this attribute.

Legacy: StoragePermanentError

Collapsed into StorageError in the shipped surface. Non-retryable failures are distinguished by context["retryable"] = False.