dbt-labs/dbt-core · error · NotImplementedError

callbacks= (EventManager hooks) are not yet supported.

Error message

callbacks= (EventManager hooks) are not yet supported.

What it means

NotImplementedError raised in DbtRunner.__init__ when a caller passes callbacks= (EventManager hooks) to the constructor. The callback/EventManager hook API from dbt-core's dbtRunner has not been ported to this runner yet, so any non-None callbacks argument is rejected at construction time.

Source

Thrown at crates/dbt-sa-python/python/dbt/runner.py:111

            argv += [flag, str(value)]
    return argv


class dbtRunner:
    """In-process dbt runner. Reuse one instance across calls."""

    # Each invoke() gets its own log file, verbosity and warn-error options. Concurrent
    # invokes are serialized, since a run's log layers are installed process-wide.
    # `--log-level trace` acts as `debug`: the subscriber's cap is fixed per process.

    def __init__(self, manifest: Any = None, callbacks: Any = None):
        if manifest is not None:
            raise NotImplementedError(
                "manifest= injection is not yet supported. Reuse the runner "
                "instance across invocations to avoid re-parsing."
            )
        if callbacks is not None:
            raise NotImplementedError("callbacks= (EventManager hooks) are not yet supported.")
        self._runner = _DbtRunner()

    def invoke(self, args: List[str], **kwargs) -> dbtRunnerResult:
        argv = list(args) + _kwargs_to_cli(kwargs)
        try:
            core = self._runner.invoke(argv)
        except (KeyboardInterrupt, SystemExit):
            raise
        except BaseException as exc:
            # Parse errors and caught panics: hand back on the result, don't
            # kill the interpreter.
            return dbtRunnerResult(success=False, result=None, exception=exc)
        # Engine reports errors on the result, not by raising; surface the message.
        exception = DbtRunnerError(core.exception) if core.exception else None
        catalog = (
            CatalogArtifact.from_msgpack(core.catalog_msgpack)
            if core.catalog_msgpack is not None
            else None

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Remove the callbacks= argument from the DbtRunner constructor.
  2. Capture progress via dbt's log output or the returned dbtRunnerResult instead of event hooks.
  3. Use the official dbt-core dbtRunner if event callbacks are essential to your integration.
  4. Wrap log handling externally (e.g. configure log levels/formatting via invoke kwargs like --log-level).

Example fix

// before
runner = DbtRunner(callbacks=[lambda e: print(e)])
// after
runner = DbtRunner()
result = runner.invoke(["run"])
print(result.success, result.exception)
Defensive patterns

Strategy: try-catch

Validate before calling

if callbacks:
    print('callbacks= not supported by this DbtRunner; use log capture or dbtRunnerResult instead')

Type guard

def runner_supports_callbacks(runner_cls) -> bool:
    import inspect
    src = inspect.getsource(runner_cls.__init__)
    return 'callbacks=' in inspect.signature(runner_cls.__init__).parameters and 'not yet supported' not in src

Try / catch

try:
    runner = DbtRunner(callbacks=[on_event])
except NotImplementedError:
    runner = DbtRunner()  # capture progress from result/log output instead

Prevention

When it happens

Trigger: Calling DbtRunner(callbacks=[my_callback]) or DbtRunner(manifest=..., callbacks=...) — any non-None callbacks argument to __init__.

Common situations: Porting dbt-core dbtRunner code that registered event callbacks for logging/progress tracking; integrating with monitoring systems that hook dbt events; following dbt-core documentation examples.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/2065c795e0a6a327. Report an issue: GitHub.