mono/mono · critical

Error: Loaded assembly '%s' doesn't match original file name

Error message

Error: Loaded assembly '%s' doesn't match original file name '%s'. Set MONO_PATH to the assembly's location.

What it means

In AOT mode, after loading an assembly Mono re-opens the same filename with mono_image_open and compares img->name against assembly->image->name. If they differ, the loader resolved the file to a different assembly than the one matched by name (an assembly-identity mismatch), and it exits(1). The message tells the user to set MONO_PATH to the assembly's real location.

Source

Thrown at mono/mini/driver.c:1441

		for (i = 0; i < main_args->argc; ++i) {
			assembly = mono_domain_assembly_open_internal (main_args->domain, mono_domain_default_alc (main_args->domain), main_args->argv [i]);
			if (!assembly) {
				if (mono_is_problematic_file (main_args->argv [i])) {
					fprintf (stderr, "Info: AOT of problematic assembly %s skipped. This is expected.\n", main_args->argv [i]);
					continue;
				} else {
					fprintf (stderr, "Can not open image %s\n", main_args->argv [i]);
					exit (1);
				}
			}
			/* Check that the assembly loaded matches the filename */
			{
				MonoImageOpenStatus status;
				MonoImage *img;

				img = mono_image_open (main_args->argv [i], &status);
				if (img && strcmp (img->name, assembly->image->name)) {
					fprintf (stderr, "Error: Loaded assembly '%s' doesn't match original file name '%s'. Set MONO_PATH to the assembly's location.\n", assembly->image->name, img->name);
					exit (1);
				}
			}
			res = mono_compile_assembly (assembly, main_args->opts, main_args->aot_options, &aot_state);
			if (res != 0) {
				fprintf (stderr, "AOT of image %s failed.\n", main_args->argv [i]);
				exit (1);
			}
		}
		if (aot_state) {
			res = mono_compile_deferred_assemblies (main_args->opts, main_args->aot_options, &aot_state);
			if (res != 0) {
				fprintf (stderr, "AOT of mode-specific deferred assemblies failed.\n");
				exit (1);
			}
		}
	} else {
		assembly = mono_domain_assembly_open_internal (main_args->domain, mono_domain_default_alc (main_args->domain), main_args->file);

View on GitHub (pinned to 0f53e9e151)

Solutions

  1. Set MONO_PATH to the exact directory containing the assembly you intend to AOT: export MONO_PATH=/abs/path/to/asm.
  2. Remove or rename the conflicting same-named assembly elsewhere in the search path.
  3. Pass the full absolute path to --aot instead of relying on search.
  4. Verify the assembly's AssemblyName matches the file's expected identity (monodis --assembly).

Example fix

# before: MONO_PATH resolves a different Newtonsoft.Json
mono --aot Newtonsoft.Json.dll
# after
MONO_PATH=/app/libs mono --aot /app/libs/Newtonsoft.Json.dll
Defensive patterns

Strategy: validation

Validate before calling

# Ensure the requested file's AssemblyName matches what mono will resolve
monodis --assembly "$ASM" | grep -q "Name: $EXPECTED" || { echo "identity mismatch"; exit 1; }
export MONO_PATH="$(cd "$(dirname "$ASM")" && pwd)"

Prevention

When it happens

Trigger: MONO_PATH or the default search path causes Mono to load an assembly whose AssemblyName does not match the file requested — typically because a different version or a same-named assembly in another directory was picked up. The strong/simple name comparison fails.

Common situations: Multiple assemblies with the same filename in different directories; MONO_PATH pointing at a shared GAC-like folder with a different version; shadow-copy or packaging putting the wrong file at the expected name; case-insensitive filesystem collisions.

Related errors


AI-assisted analysis of mono/mono@0f53e9e151 (2026-08-13). Data as JSON: /api/errors/ec36f123c4e5dd38. Report an issue: GitHub.