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

  1. 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.
  2. Remove max-heap-size from MONO_GC_PARAMS if no hard ceiling is required.
  3. Switch to sgen (MONO_GC_PARAMS=sgen) if you need finer-grained or smaller-heap control, as this limit is Boehm-specific.
  4. 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

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


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)