dotnet/runtime · error
coreclr_shutdown_2 failed - Error: 0x%08x
Error message
coreclr_shutdown_2 failed - Error: 0x%08x
What it means
Printed in corerun_shutdown() when coreclr_shutdown_2() returns a failing HRESULT. The managed Main already executed and produced an exit code; this is a best-effort shutdown failure. The host forces exit_code = -1 so the process reports failure even if Main returned success.
Source
Thrown at src/coreclr/hosts/corerun/corerun.cpp:689
}
#endif // TARGET_WASI
return final_exit_code;
#endif // TARGET_BROWSER
}
extern "C" int corerun_shutdown(int exit_code)
{
coreclr_shutdown_2_ptr coreclr_shutdown2_func = nullptr;
if (!try_get_export(coreclr_mod, "coreclr_shutdown_2", (void**)&coreclr_shutdown2_func))
{
return -1;
}
int latched_exit_code = 0;
int result = coreclr_shutdown2_func(CurrentClrInstance, CurrentAppDomainId, &latched_exit_code);
if (FAILED(result))
{
pal::fprintf(stderr, W("coreclr_shutdown_2 failed - Error: 0x%08x\n"), result);
exit_code = -1;
}
if (exit_code != -1)
exit_code = latched_exit_code;
::free((void*)s_core_libs_path);
::free((void*)s_core_root_path);
return exit_code;
}
// Display the command line options
static void display_usage()
{
pal::fprintf(
stderr,
W("USAGE: corerun [OPTIONS] assembly [ARGUMENTS]\n")
W("\n")View on GitHub (pinned to 290d5ab72c)
Solutions
- Treat shutdown failure as non-fatal for the user's result but investigate lingering managed threads or background work in Main.
- Ensure Main returns / awaits all tasks before exiting so no foreground threads block shutdown.
- Avoid double-shutdown (calling corerun_shutdown twice) — the runtime tears down once.
- If reproducible only under load, profile for threads that ignore cancellation.
Example fix
// before: Main leaves a foreground thread running
static void Main() { new Thread(() => while(true){}) { IsBackground=false }.Start(); }
// after: mark background or exit cleanly
static void Main() { using var cts = new CancellationTokenSource(); new Thread(Work){IsBackground=true}.Start(); cts.Cancel(); } Defensive patterns
Strategy: validation
Validate before calling
// managed-side: ensure Main awaits all work and no foreground threads linger
static async Task Main()
{
using var cts = new CancellationTokenSource();
var t = Task.Run(() => Worker(cts.Token));
cts.CancelAfter(TimeSpan.FromSeconds(30));
await t; // do not return until work is done
} Prevention
- Ensure Main awaits all outstanding tasks before returning.
- Mark long-running worker threads as background (IsBackground=true).
- Never call corerun_shutdown twice.
- Treat a shutdown-2 failure as a symptom of incomplete cleanup, not the root cause.
When it happens
Trigger: coreclr_shutdown2_func(CurrentClrInstance, CurrentAppDomainId, &latched_exit_code) returns FAILED. Common when: shutdown is called on an already-torn-down runtime, a managed thread refused to stop, or a graceful shutdown timed out.
Common situations: Managed code left foreground threads running; native shutdown called twice; a pinned/unloadable assembly blocked teardown; runtime was only partially initialized due to an earlier recoverable error.
Related errors
- BEGIN: coreclr_initialize failed - Error: 0x%08x
- END: coreclr_initialize failed - Error: 0x%08x
- BEGIN: coreclr_execute_assembly failed - Error: 0x%08x
- END: coreclr_execute_assembly failed - Error: 0x%08x
- Export '%s' not found.
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/da234fe56bac7620.
Report an issue: GitHub.