Flow-Launcher/Flow.Launcher · error · Exception
<JSON-RPC plugin error stream output>
Error message
<JSON-RPC plugin error stream output>
What it means
Thrown as a plain Exception whose message is the entire stderr of the V2 JSON-RPC plugin process, read to end during InitAsync. Unlike v1, the read is fire-and-forget (_ = ReadErrorAsync()) so the throw happens on a detached task — it will surface as an unobserved task exception / may not propagate cleanly to the caller of InitAsync. V2 plugins use StreamJsonRpc over stdin/stdout pipes, and stderr is reserved exclusively for fatal diagnostics.
Source
Thrown at Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs:74
}
public override async Task InitAsync(PluginInitContext context)
{
await base.InitAsync(context);
SetupJsonRPC();
_ = ReadErrorAsync();
await RPC.InvokeAsync("initialize", context);
async Task ReadErrorAsync()
{
var error = await ErrorStream.ReadToEndAsync();
if (!string.IsNullOrEmpty(error))
{
throw new Exception(error);
}
}
}
public event ResultUpdatedEventHandler ResultsUpdated;
protected enum MessageHandlerType
{
HeaderDelimited,
LengthHeaderDelimited,
NewLineDelimited
}
protected abstract MessageHandlerType MessageHandler { get; }
private void SetupJsonRPC()
{
var formatter = new SystemTextJsonFormatter { JsonSerializerOptions = RequestSerializeOption };View on GitHub (pinned to 7fc63b07bb)
Solutions
- Read the message — it is the plugin process's verbatim stderr and identifies the failing component.
- Run the plugin executable directly with the same args/env Flow Launcher uses and observe its stderr.
- Confirm the plugin declares APIVersion >= 2 in plugin.json and actually speaks the V2 framed protocol, otherwise stderr noise from a v1-style plugin will trip this.
- Because ReadErrorAsync is fire-and-forget, the exception may not bubble to the UI — check Flow Launcher's logs/UnobservedTaskException handler for the real message.
- Reinstall or update the plugin.
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
// ReadErrorAsync is fire-and-forget — wrap InitAsync and observe the detached task
try { await plugin.InitAsync(context); }
catch (Exception ex) { Context.API.LogException(ClassName, $"V2 plugin init failed: {ex.Message}", ex); } Prevention
- Because ReadErrorAsync is detached, attach an exception handler: _ = ReadErrorAsync().ContinueWith(t => Log(...), TaskContinuationOptions.OnlyOnFaulted).
- Keep V2 plugin stderr clean — route logs to a file.
- Verify the plugin's declared APIVersion matches the V2 protocol before load.
- Monitor Flow Launcher's unobserved-task-exception logs for hidden V2 init failures.
When it happens
Trigger: The V2 plugin process writes any non-empty string to its ErrorStream during the lifetime of InitAsync (which spans the initialize RPC call). The throw fires after ErrorStream.ReadToEndAsync completes, i.e. when the pipe closes (process exit) or EOF is reached.
Common situations: V2 plugin runtime missing or wrong version; plugin crashes during its initialize handler and dumps a stack trace to stderr; a native dependency of the plugin fails to load and writes to stderr before the RPC handshake completes; mixing a debug build that prints to stderr.
Related errors
AI-assisted analysis of Flow-Launcher/Flow.Launcher@7fc63b07bb (2026-08-13).
Data as JSON: /api/errors/575e1c0419cb4fb7.
Report an issue: GitHub.