NousResearch/hermes-agent · error · TypeError

register_provider() expects a TranscriptionProvider instance

Error message

register_provider() expects a TranscriptionProvider instance, got {type(provider).__name__}

What it means

TypeError raised by TranscriptionProviderRegistry.register_provider() (agent/transcription_registry.py:73) when the object passed is not an instance of the TranscriptionProvider ABC. The registry enforces the ABC contract up front so a malformed plugin fails loudly at registration rather than silently breaking dispatch later.

Source

Thrown at agent/transcription_registry.py:73

_lock = threading.Lock()


def register_provider(provider: TranscriptionProvider, *, scope: Optional[str] = None) -> None:
    """Register a transcription provider.

    Rejects:

    - Non-:class:`TranscriptionProvider` instances (raises :class:`TypeError`).
    - Empty/whitespace ``.name`` (raises :class:`ValueError`).
    - Names colliding with a built-in (logs a warning, silently
      ignores — built-ins-always-win invariant).

    Re-registration (same ``name``) overwrites the previous entry and
    logs a debug message — makes hot-reload scenarios (tests, dev
    loops) behave predictably.
    """
    if not isinstance(provider, TranscriptionProvider):
        raise TypeError(
            f"register_provider() expects a TranscriptionProvider instance, "
            f"got {type(provider).__name__}"
        )
    name = provider.name
    if not isinstance(name, str) or not name.strip():
        raise ValueError("Transcription provider .name must be a non-empty string")
    key = name.strip().lower()
    if key in _BUILTIN_NAMES:
        logger.warning(
            "Transcription provider '%s' shadows a built-in name; registration "
            "ignored. Built-in STT providers (%s) always win — pick a different "
            "name.",
            key, ", ".join(sorted(_BUILTIN_NAMES)),
        )
        return
    with _lock:
        target = _providers if scope is None else _scoped_providers.setdefault(scope, {})
        existing = target.get(key)

View on GitHub (pinned to c896c09c42)

Solutions

  1. Instantiate before registering: register_provider(MyProvider()) instead of register_provider(MyProvider).
  2. Import the ABC from the canonical location (agent.transcription_registry / the module that owns it) so isinstance matches.
  3. If the object is duck-typed on purpose, subclass TranscriptionProvider so the contract is explicit.

Example fix

# before
from my_stt import MyProvider  # different base class
register_provider(MyProvider)   # TypeError: got 'type'

# after
from agent.transcription_registry import TranscriptionProvider

class MyProvider(TranscriptionProvider):  # implement the ABC
    ...

register_provider(MyProvider())
Defensive patterns

Strategy: type-guard

Validate before calling

from agent.transcription_registry import TranscriptionProvider, register_provider

def safe_register(provider) -> None:
    if not isinstance(provider, TranscriptionProvider):
        raise TypeError(f"expected TranscriptionProvider, got {type(provider).__name__}")
    register_provider(provider)

Type guard

from agent.transcription_registry import TranscriptionProvider

def is_transcription_provider(obj: object) -> bool:
    return isinstance(obj, TranscriptionProvider)

Try / catch

try:
    register_provider(provider)
except TypeError as exc:
    logger.error("plugin registration failed (not a TranscriptionProvider): %s", exc)

Prevention

When it happens

Trigger: Calling register_provider(some_obj) where some_obj is e.g. a class (not an instance), a duck-typed object missing the ABC, a provider built against an older/different TranscriptionProvider base class, or None.

Common situations: A third-party STT plugin registers the class instead of an instance (register_provider(MyProvider)), or imports TranscriptionProvider from a vendored/copied module so isinstance fails despite identical shape; refactors that moved the ABC leave stale imports.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/8ab0f39827e9c4a7. Report an issue: GitHub.