dbt-labs/dbt-core · error · NotImplementedError

manifest= injection is not yet supported. Reuse the runner i

Error message

manifest= injection is not yet supported. Reuse the runner instance across invocations to avoid re-parsing.

What it means

NotImplementedError raised in DbtRunner.__init__ when a caller passes manifest= to the constructor. This Python runner port does not yet support injecting a pre-parsed manifest object; runs must parse the manifest themselves. The error message directs users to reuse a single runner instance across invocations instead.

Source

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

            argv.append(flag if value else "--no-" + key.replace("_", "-"))
        elif isinstance(value, (list, tuple)):
            for item in value:
                argv += [flag, str(item)]
        else:
            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.

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Remove the manifest= argument and let the runner parse the manifest from the project on each invoke.
  2. Reuse a single DbtRunner instance across invocations so the parsed manifest is cached internally, avoiding re-parsing.
  3. If manifest injection is essential, use the official dbt-core dbtRunner instead of this port.
  4. File/request feature support for manifest= injection in this runner.

Example fix

// before
runner = DbtRunner(manifest=manifest)
// after
runner = DbtRunner()  # reuse this instance across invoke() calls to avoid re-parsing
runner.invoke(["run"])
Defensive patterns

Strategy: try-catch

Validate before calling

import inspect
sig = inspect.signature(DbtRunner.__init__)
if 'manifest' in sig.parameters:
    print('manifest param exists but raises NotImplementedError in this runner')

Type guard

def runner_supports_manifest_injection(runner_cls) -> bool:
    import inspect
    src = inspect.getsource(runner_cls.__init__)
    return 'manifest= injection is not yet supported' not in src

Try / catch

try:
    runner = DbtRunner(manifest=manifest)
except NotImplementedError:
    runner = DbtRunner()  # fall back: let runner parse and cache internally

Prevention

When it happens

Trigger: Calling DbtRunner(manifest=my_manifest) — any non-None manifest argument to __init__.

Common situations: Porting code from the official dbt-core dbtRunner (which supports manifest=) to this Rust-backed runner; trying to cache a parsed manifest across invocations for performance; copying example code from dbt-core docs.

Related errors


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