{"record":{"id":"fa80eb6a71b42616","repo":"devlooped/moq","slug":"the-return-type-of-the-last-member-shown-above-is-not","errorCode":null,"errorMessage":"The return type of the last member shown above is not mockable.","messagePattern":"The return type of the last member shown above is not mockable\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Moq/ActionObserver.cs","lineNumber":307,"sourceCode":"                    this.invocation = invocation;\n                    this.invocationTimestamp = this.matcherObserver.GetNextTimestamp();\n\n                    if (returnType == typeof(void))\n                    {\n                        this.returnValue = null;\n                    }\n                    else if (AwaitableFactory.TryGet(returnType) is { } awaitableFactory)\n                    {\n                        var result = CreateProxy(awaitableFactory.ResultType, null, this.matcherObserver, out _);\n                        this.returnValue = awaitableFactory.CreateCompleted(result);\n                    }\n                    else if (returnType.IsMockable())\n                    {\n                        this.returnValue = CreateProxy(returnType, null, this.matcherObserver, out _);\n                    }\n                    else\n                    {\n                        throw new NotSupportedException(Resources.LastMemberHasNonInterceptableReturnType);\n                    }\n                }\n\n                if (returnType != typeof(void))\n                {\n                    invocation.ReturnValue = this.returnValue;\n                }\n            }\n        }\n    }\n}\n","sourceCodeStart":289,"sourceCodeEnd":319,"githubUrl":"https://github.com/devlooped/moq/blob/89a5be629c752960fe403e95ff583e4ae6f00542/src/Moq/ActionObserver.cs#L289-L319","documentation":"While intercepting a delegate-based setup, Moq walks the member chain and must return a value for the last member. If that member's return type is not mockable (e.g. a sealed class, struct, or other non-proxyable type), Moq cannot create a proxy to continue the chain and throws NotSupportedException: 'The return type of the last member shown above is not mockable.'","triggerScenarios":"A lambda in an ActionObserver/observer setup accesses a chain whose final property/method returns a non-mockable type — sealed classes, structs, strings, or types without an accessible constructor — so CreateProxy cannot build the intermediate mock.","commonSituations":"Chaining into a struct-typed property (DateTime, Guid, custom structs); accessing properties returning sealed framework types; deep navigation past the last mockable member; setting up a delegate that reads data rather than invoking an overridable member.","solutions":["Make the last member's return type mockable: change it to an interface or a non-sealed class with a parameterless constructor.","Restructure the setup so the chain stops at the last mockable member and set up the non-mockable value directly.","If the member must return a value type/sealed type, use a conventional `mock.SetupGet(x => x.Member).Returns(value)` instead of chain continuation.","Verify with a mockable-type check (similar to Moq's `IsMockable()`) before writing chain-based setups."],"exampleFix":"// before\nmock.SetupAction(x => x.Session.Timestamp.Now); // struct DateTime not mockable\n// after\nmock.SetupGet(x => x.Session.Timestamp).Returns(new DateTime(2026, 1, 1));","handlingStrategy":"type-guard","validationCode":"// Check the last member's return type before chain setup\nvar returnType = lastMemberProperty.PropertyType;\nbool mockable = !returnType.IsValueType && !returnType.IsSealed && returnType.GetConstructor(Type.EmptyTypes) != null;","typeGuard":"static bool IsMockable(Type t) =>\n    !t.IsValueType && (!t.IsSealed || t.IsInterface) && !t.IsPrimitive;","tryCatchPattern":"try\n{\n    mock.SetupAction(lambda);\n}\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"not mockable\"))\n{\n    // set up the leaf value directly via SetupGet/Returns instead\n}","preventionTips":["End chains at interface-typed or open-class members","Never chain past value-typed (struct) or sealed members","Use SetupGet().Returns(...) for leaf values that cannot be proxied","Keep DTO/leaf types out of mock navigation chains"],"tags":["moq","not-supported","mockability","sealed-type"],"backgroundTag":"unsupported-operation","analyzedSha":"89a5be629c752960fe403e95ff583e4ae6f00542","analyzedAt":"2026-09-16T05:31:39.496Z","contentChangedAt":"2026-09-16T05:31:39.496Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}