dotnet/runtime · critical
max-heap-size must be at least %dMb.\n
Error message
max-heap-size must be at least %dMb.\n
What it means
During Mono's Boehm GC initialization the runtime parses the MONO_GC_PARAMS environment variable. The max-heap-size option is accepted only if its value is at least MIN_BOEHM_MAX_HEAP_SIZE_IN_MB (16 MB). Below that, the GC refuses to start and prints this message followed by exit(1), because a smaller heap would be unusable/contradict GC internals.
Solutions
- Set max-heap-size to at least 16m, e.g. MONO_GC_PARAMS=max-heap-size=64m, and tune upward if the app needs headroom.
- Remove max-heap-size from MONO_GC_PARAMS if no hard ceiling is required.
- Switch to sgen (MONO_GC_PARAMS=sgen) if you need finer-grained or smaller-heap control, as this limit is Boehm-specific.
- Validate the number suffix: bare N is megabytes; k/m/g suffixes multiply, so 16m is 16 MB and 16k is far below the floor.
Example fix
# before export MONO_GC_PARAMS=max-heap-size=8m # after export MONO_GC_PARAMS=max-heap-size=64m
Defensive patterns
Strategy: validation
Validate before calling
#!/usr/bin/env bash
# Validate MONO_GC_PARAMS max-heap-size is >= 16MB before launching Mono (Boehm).
set -euo pipefail
val="${MONO_GC_PARAMS:-}"
if [[ "$val" =~ max-heap-size=([0-9]+)([kKmMgG]?) ]]; then
num="${BASH_REMATCH[1]}"; unit="${BASH_REMATCH[2]}"
case "$unit" in
k|K) mb=$(( num / 1024 ));;
g|G) mb=$(( num * 1024 ));;
*) mb="$num";;
esac
[ "$mb" -ge 16 ] || { echo "max-heap-size must be >=16m"; exit 1; }
fi Prevention
- Always set max-heap-size to at least 16m (the Boehm floor).
- Remember a bare number is megabytes; use the m suffix explicitly.
- Prefer sgen if you need fine-grained or smaller-heap control.
- Validate MONO_GC_PARAMS in deployment scripts before app launch.
When it happens
Trigger: Launching a Mono (Boehm GC) process with MONO_GC_PARAMS containing max-heap-size=N where N parses to fewer than 16 megabytes (e.g. max-heap-size=8, max-heap-size=10m, max-heap-size=1m). The check fires at GC init, before user code runs.
Common situations: Trying to constrain memory tightly on embedded/container workloads and setting an unrealistically small ceiling; typos or wrong unit suffix (max-heap-size=16k meaning 16 kilobytes); copying a config from a sgen-tuned app where smaller numbers were intended.
Related errors
- max-heap-size must be an integer.\n
- Precise stack mark not supported - disabling.\n
- Warning: Could not open bridge dump file
- Can't use moduleFactory callback of createDotnetRuntime…
- Invalid config, resources is not set
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/a55824b6902fa31d.
Report an issue: GitHub.
Appendix: source
Thrown at src/mono/mono/metadata/boehm-gc.c:171
GC_set_warn_proc (mono_gc_warning);
GC_set_finalize_on_demand (1);
GC_set_finalizer_notifier(mono_gc_finalize_notify);
GC_init_gcj_malloc (5, NULL);
GC_allow_register_threads ();
if ((env = g_getenv ("MONO_GC_PARAMS"))) {
char **ptr, **opts = g_strsplit (env, ",", -1);
for (ptr = opts; *ptr; ++ptr) {
char *opt = *ptr;
if (g_str_has_prefix (opt, "max-heap-size=")) {
size_t max_heap;
opt = strchr (opt, '=') + 1;
if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) {
fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB);
exit (1);
}
GC_set_max_heap_size (max_heap);
} else {
fprintf (stderr, "max-heap-size must be an integer.\n");
exit (1);
}
continue;
} else if (g_str_has_prefix (opt, "toggleref-test")) {
register_test_toggleref_callback ();
continue;
} else {
/* Could be a parameter for sgen */
/*
fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
exit (1);
*/View on GitHub (pinned to 60108ba66e)