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
- Add the missing case to emit_marshal_handleref_ilgen for the new MarshalAction value and emit the correct IL (mirror the SafeHandle/object handlers).
- If seen unexpectedly on a stock runtime, report it as a Mono runtime bug: the switch must cover every MarshalAction member.
- 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 adding a MarshalAction enum member, update every emit_marshal_*_ilgen switch in the same change.
- Add a unit test that enumerates MarshalAction against each switch to prevent regressions.
- Treat seeing this message on a stock runtime as a bug to report upstream.
- Code-review interop marshaller changes for switch completeness.
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
- mono/marshal: SafeHandles missing MANAGED_CONV_IN\n
- mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n
- mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n
- Invalid jsThreadBlockingMode
- socket() failed: %s\n
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/2f07af4f0241b618.
Report an issue: GitHub.