dotnet/runtime · warning
Precise stack mark not supported - disabling.\n
Error message
Precise stack mark not supported - disabling.\n
What it means
During SGen's thread scan (sgen_client_scan_thread_data), a precise stack mark requires mono_gc_get_gc_callbacks()->thread_mark_func to be registered. When a thread is on the imprecise pass, precise marking was requested, but no thread_mark_func exists, SGen logs this once, sets the static conservative_stack_mark flag to TRUE, and pins the thread stack conservatively. Note sgen_client_init already defaults conservative_stack_mark=TRUE with the comment 'Precise marking is broken on all supported targets. Disable until fixed.', so this message only appears when precise is explicitly requested and unsupported.
Source
Thrown at src/mono/mono/metadata/sgen-mono.c:2128
*/
HandleStack *stack = info->client_info.info.handle_stack;
g_assert (stack == NULL || mono_handle_stack_is_empty (stack));
}
continue;
}
g_assert (info->client_info.stack_start);
g_assert (info->client_info.info.stack_end);
aligned_stack_start = get_aligned_stack_start (info);
g_assert (info->client_info.suspend_done);
if (!debug_coop_no_stack_scan) {
SGEN_LOG (3, "Scanning thread %p, range: %p-%p, size: %" G_GSIZE_FORMAT "d, pinned=%" G_GSIZE_FORMAT "d", info, info->client_info.stack_start, info->client_info.info.stack_end, (char*)info->client_info.info.stack_end - (char*)info->client_info.stack_start, sgen_get_pinned_count ());
if (mono_gc_get_gc_callbacks ()->thread_mark_func && !conservative_stack_mark) {
mono_gc_get_gc_callbacks ()->thread_mark_func (info->client_info.runtime_data, (guint8 *)aligned_stack_start, (guint8 *)info->client_info.info.stack_end, precise, &ctx);
} else if (!precise) {
if (!conservative_stack_mark) {
fprintf (stderr, "Precise stack mark not supported - disabling.\n");
conservative_stack_mark = TRUE;
}
//FIXME we should eventually use the new stack_mark from coop
sgen_conservatively_pin_objects_from ((void **)aligned_stack_start, (void **)info->client_info.info.stack_end, start_nursery, end_nursery, PIN_TYPE_STACK);
}
if (!precise) {
sgen_conservatively_pin_objects_from ((void**)&info->client_info.ctx, (void**)(&info->client_info.ctx + 1),
start_nursery, end_nursery, PIN_TYPE_STACK);
{
// This is used on Coop GC for platforms where we cannot get the data for individual registers.
// We force a spill of all registers into the stack and pass a chunk of data into sgen.
//FIXME under coop, for now, what we need to ensure is that we scan any extra memory from info->client_info.info.stack_end to stack_mark
MonoThreadUnwindState *state = &info->client_info.info.thread_saved_state [SELF_SUSPEND_STATE_INDEX];
if (state && state->gc_stackdata) {
sgen_conservatively_pin_objects_from ((void **)state->gc_stackdata, (void**)((char*)state->gc_stackdata + state->gc_stackdata_size),
start_nursery, end_nursery, PIN_TYPE_STACK);View on GitHub (pinned to 60108ba66e)
Solutions
- Remove 'stack-mark=precise' from MONO_GC_PARAMS and rely on the default conservative marking
- Use a runtime/platform build that registers thread_mark_func (a cooperative-GC-enabled build) if precise marking is required
- Treat the message as informational: GC correctness is preserved via the automatic conservative fallback, only precision/pinning behavior changes
Example fix
# before export MONO_GC_PARAMS=stack-mark=precise # after # omit the option; default conservative stack marking is used export MONO_GC_PARAMS=
Defensive patterns
Strategy: fallback
Validate before calling
// After the runtime is initialized, query whether precise marking actually took effect.
// mono_gc_precise_stack_mark_enabled() returns !conservative_stack_mark (gc-internals.h:363).
#include <mono/metadata/mono-gc.h>
gboolean want_precise = g_getenv ("MONO_GC_PARAMS") != NULL; // your own logic
if (want_precise && !mono_gc_precise_stack_mark_enabled ()) {
g_print ("Precise stack marking is not available on this platform/runtime; "
"GC will run in conservative mode.\n");
} Prevention
- Don't set 'stack-mark=precise' unless you have confirmed the platform/runtime registers a GC thread_mark_func
- After init, call mono_gc_precise_stack_mark_enabled() to verify the requested mode actually engaged rather than trusting the env var
- Treat the message as benign: GC correctness is unaffected; only the amount of conservative pinning changes
- When embedding Mono, install the cooperative-GC thread-mark callback if you need precise marking instead of relying on the env var alone
When it happens
Trigger: Setting MONO_GC_PARAMS=stack-mark=precise on a runtime or platform that does not register a GC thread_mark_func (i.e. without the cooperative GC's thread-mark callback). Emitted at most once per process because it flips the global conservative_stack_mark flag on first occurrence.
Common situations: Opting into precise stack marking to reduce false pinning on a platform where it isn't implemented; embedding Mono in a custom host that does not install the GC thread-mark callback; running on an older/newer runtime whose platform support for precise marking changed.
Related errors
- max-heap-size must be at least %dMb.\n
- max-heap-size must be an integer.\n
- Warning: Could not open bridge dump file `%s` for writing: %
- Unrecognized asset behavior:${asset.behavior}, for asset ${a
- method instrumentation is not enabled, please enable it with
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/0cf1e0ffa274fee8.
Report an issue: GitHub.