icsharpcode/ILSpy · error · BadImageFormatException

Invalid metadata token

Error message

Invalid metadata token

What it means

BadImageFormatException thrown by ReadAndDecodeMetadataToken when the 4-byte token read from the IL stream is <= 0. SRM (System.Reflection.Metadata) uses negative integers as 'virtual tokens' and gets confused if one is fabricated, and row ids below 1 are never valid, so a non-positive token signals a corrupted or truncated method body.

Source

Thrown at ICSharpCode.Decompiler/IL/ILReader.cs:223

				v.InitialValueIsInitialized = body.LocalVariablesInitialized;
				v.UsesInitialValue = true;
			}
			this.mainContainer = new BlockContainer(expectedResultType: methodReturnStackType);
			this.blocksByOffset.Clear();
			this.importQueue.Clear();
			this.isBranchTarget = new BitSet(reader.Length);
			this.variableByExceptionHandler.Clear();
		}

		EntityHandle ReadAndDecodeMetadataToken()
		{
			int token = reader.ReadInt32();
			if (token <= 0)
			{
				// SRM uses negative tokens as "virtual tokens" and can get confused
				// if we manually create them.
				// Row-IDs < 1 are always invalid.
				throw new BadImageFormatException("Invalid metadata token");
			}
			var handle = MetadataTokens.EntityHandle(token);
			if (handle.IsNil)
			{
				// The runtime will crash with a BadImageFormatException when it encounters a row-ID of 0.
				// We assume the code following this instruction to be unreachable.
				throw new BadImageFormatException("Invalid metadata token");
			}
			return handle;
		}

		IType ReadAndDecodeTypeReference()
		{
			var typeReference = ReadAndDecodeMetadataToken();
			return module.ResolveType(typeReference, genericContext);
		}

		IMethod ReadAndDecodeMethodReference()

View on GitHub (pinned to 60c08fcb74)

Solutions

  1. Treat the assembly as untrusted input and wrap decompilation in try/catch for BadImageFormatException.
  2. Verify the file is a valid managed PE before decompiling (e.g. PEReader.IsEntireImageAvailable / check the PE header).
  3. Re-acquire a clean copy of the assembly if the stream is truncated.

Example fix

// before
var result = decompiler.DecompileAssembly(assemblyPath);

// after
try
{
    var result = decompiler.DecompileAssembly(assemblyPath);
}
catch (BadImageFormatException ex)
{
    logger.Warn($"Corrupt assembly {assemblyPath}: {ex.Message}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

bool IsValidPe(string path)
{
    try { using var pe = new PEReader(File.OpenRead(path)); return pe.PEHeaders != null; }
    catch { return false; }
}

Try / catch

try { var code = decompiler.DecompileTypeAsString(typeName); }
catch (BadImageFormatException ex) { logger.Warn($"Corrupt IL in {assemblyPath}: {ex.Message}"); }

Prevention

When it happens

Trigger: Decompiling an assembly whose IL stream contains a garbage/negative token operand: truncated method body, hand-crafted malformed IL, or an obfuscated binary with tampered token bytes.

Common situations: Obfuscated or packed assemblies; assemblies corrupted on disk or in transit; IL emitted by a buggy/illicit code generator writing invalid token operands.

Related errors


AI-assisted analysis of icsharpcode/ILSpy@60c08fcb74 (2026-08-13). Data as JSON: /api/errors/f2674c73c705e025. Report an issue: GitHub.