dotnet/runtime · error

Unhandled case for MarshalAction: %d\n

Error message

Unhandled case for MarshalAction: %d\n

What it means

In emit_marshal_handleref_ilgen the switch over MarshalAction falls through to default when the action value is not one of the known MARSHAL_ACTION_* constants. The marshaller prints 'Unhandled case for MarshalAction: <n>' to stderr and returns conv_arg unchanged, i.e. it emits nothing for an action it does not recognize. This is effectively an internal-consistency failure: a new enum member was added to the runtime without a matching case here.

Source

Thrown at src/mono/mono/component/marshal-ilgen.c:2107

	case MARSHAL_ACTION_CONV_RESULT: {
		char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
		cb_to_mono->methodBuilder.emit_exception_marshal_directive (mb, msg);
		break;
	}

	case MARSHAL_ACTION_MANAGED_CONV_IN:
		fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
		break;

	case MARSHAL_ACTION_MANAGED_CONV_OUT:
		fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
		break;

	case MARSHAL_ACTION_MANAGED_CONV_RESULT:
		fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
		break;
	default:
		fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action);
	}
	return conv_arg;
}

static int
emit_marshal_object_ilgen (EmitMarshalContext *m, int argnum, MonoType *t,
			MonoMarshalSpec *spec,
			int conv_arg, MonoType **conv_arg_type,
			MarshalAction action)
{
	MonoMethodBuilder *mb = m->mb;
	MonoClass *klass = mono_class_from_mono_type_internal (t);
	int pos, pos2, loc;

	MonoType *int_type = cb_to_mono->get_int_type ();
	switch (action) {
	case MARSHAL_ACTION_CONV_IN:
		*conv_arg_type = int_type;

View on GitHub (pinned to 60108ba66e)

Solutions

  1. Add the missing case to emit_marshal_handleref_ilgen for the new MarshalAction value and emit the correct IL (mirror the SafeHandle/object handlers).
  2. If seen unexpectedly on a stock runtime, report it as a Mono runtime bug: the switch must cover every MarshalAction member.
  3. Ensure MarshalAction enum and all emit_marshal_*_ilgen switches are updated together in the same change.
Defensive patterns

Strategy: validation

Validate before calling

// In-tree: assert every MarshalAction enum member is handled by each emit_marshal_* switch.
static void AssertMarshalActionsCovered() {
    foreach (MarshalAction a in Enum.GetValues(typeof(MarshalAction)))
        if (!HandledActions.Contains(a))
            throw new InvalidOperationException($"emit_marshal_handleref_ilgen missing case for {a}");
}

Prevention

When it happens

Trigger: A new MarshalAction enum value is introduced in the Mono runtime and the marshaller is invoked for a HandleRef with that action before this switch is updated. Should never happen for a released enum set; indicates an in-source inconsistency.

Common situations: In-tree development: adding a MarshalAction enum member and exercising HandleRef marshalling before updating emit_marshal_handleref_ilgen; merging a runtime change without the matching marshaller update.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/2f07af4f0241b618. Report an issue: GitHub.