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
- Call (and await) StartAsync before accessing SendStream or wiring the JSON-RPC transport
- Check whether a prior StartAsync call failed and handle/retry initialization
- 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
- Always call StartAsync before accessing SendStream
- Wire JSON-RPC transport in the post-start continuation
- Handle failed StartAsync before downstream access
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
- In-process FFI runtime library not found at
- FFI runtime library not found. Looked for
- Could not determine a napi-rs prebuilds folder for FFI…
- WebSocket response bridge is not attached.
- FFI runtime library not found at
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)