github/copilot-sdk · error · InvalidOperationException

FfiRuntimeHost has not been started.

Error message

FfiRuntimeHost has not been started.

What it means

FfiRuntimeHost exposes SendStream only after StartAsync has initialized the client→server frame pipe. Accessing SendStream before the host is started throws this InvalidOperationException because the stream is still null.

Solutions

  1. Call (and await) StartAsync before accessing SendStream or wiring the JSON-RPC transport
  2. Check whether a prior StartAsync call failed and handle/retry initialization
  3. Sequence transport setup in the StartAsync continuation rather than the constructor

Example fix

// before
var host = FfiRuntimeHost.Create(libPath, null, null, args, logger);
var rpc = new JsonRpc(host.SendStream, host.ReceiveStream); // throws
// after
var host = FfiRuntimeHost.Create(libPath, null, null, args, logger);
await host.StartAsync();
var rpc = new JsonRpc(host.SendStream, host.ReceiveStream);
Defensive patterns

Strategy: validation

Validate before calling

if (!host.Started) await host.StartAsync();
var send = host.SendStream; // safe now

Type guard

bool HostReady(FfiRuntimeHost host) => host.Started; // SendStream non-null only after StartAsync

Try / catch

Stream send;
try { send = host.SendStream; }
catch (InvalidOperationException ex) when (ex.Message.Contains("has not been started")) { await host.StartAsync(); send = host.SendStream; }

Prevention

When it happens

Trigger: Reading the SendStream property before calling StartAsync, or after a failed StartAsync that never assigned the stream; accessing it from another thread while StartAsync is still running.

Common situations: Consumers wire up JSON-RPC transport at construction time instead of after start; initialization failed earlier and the null stream is hit downstream; ordering bug where the transport setup races StartAsync.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/5970464872dbbd40. Report an issue: GitHub.

Appendix: source

Thrown at dotnet/src/FfiRuntimeHost.cs:68

    private uint _serverId;
    private uint _connectionId;
    private bool _disposed;

    private FfiRuntimeHost(string libraryPath, string? cliEntrypoint, IReadOnlyDictionary<string, string>? environment, IReadOnlyList<string> args, ILogger logger)
    {
        _libraryPath = libraryPath;
        _cliEntrypoint = cliEntrypoint;
        _environment = environment;
        _args = args;
        _logger = logger;
    }

    /// <summary>The stream JSON-RPC reads server→client frames from.</summary>
    public Stream ReceiveStream => _receiveStream;

    /// <summary>The stream JSON-RPC writes client→server frames to.</summary>
    public Stream SendStream => _sendStream
        ?? throw new InvalidOperationException("FfiRuntimeHost has not been started.");

    /// <summary>
    /// Loads the runtime cdylib and prepares the FFI host.
    /// </summary>
    public static FfiRuntimeHost Create(string libraryPath, string? cliEntrypoint, IReadOnlyDictionary<string, string>? environment, IReadOnlyList<string> args, ILogger logger)
    {
        var fullLibraryPath = Path.GetFullPath(libraryPath);
        if (!File.Exists(fullLibraryPath))
        {
            throw new InvalidOperationException($"FFI runtime library not found at '{fullLibraryPath}'.");
        }
        PrepareNativeLibrary(fullLibraryPath);
        return new FfiRuntimeHost(
            fullLibraryPath,
            cliEntrypoint is null ? null : Path.GetFullPath(cliEntrypoint),
            environment,
            args,
            logger);

View on GitHub (pinned to cd8cf15dc3)