{"record":{"id":"1bb160aff47e66b1","repo":"microsoft/aspire","slug":"handle-handleid-contains-obj-gettype-fullname-expected","errorCode":null,"errorMessage":"Handle '{handleId}' contains {obj.GetType().FullName}, expected {typeof(T).FullName}","messagePattern":"Handle '(.+?)' contains (.+?), expected (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.RemoteHost/Ats/HandleRegistry.cs","lineNumber":98,"sourceCode":"        {\n            throw new InvalidOperationException($\"Handle '{handleId}' not found in registry\");\n        }\n        return entry.Object;\n    }\n\n    /// <summary>\n    /// Gets the underlying object for a handle, cast to the specified type.\n    /// </summary>\n    /// <typeparam name=\"T\">The expected type.</typeparam>\n    /// <param name=\"handleId\">The handle ID.</param>\n    /// <returns>The underlying object.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the handle is not found or type doesn't match.</exception>\n    public T GetObject<T>(string handleId) where T : class\n    {\n        var obj = GetObject(handleId);\n        if (obj is not T typed)\n        {\n            throw new InvalidOperationException(\n                $\"Handle '{handleId}' contains {obj.GetType().FullName}, expected {typeof(T).FullName}\");\n        }\n        return typed;\n    }\n\n    /// <summary>\n    /// Gets the ATS type ID for a handle.\n    /// </summary>\n    /// <param name=\"handleId\">The handle ID.</param>\n    /// <returns>The ATS type ID.</returns>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the handle is not found.</exception>\n    public string GetTypeId(string handleId)\n    {\n        if (!_handles.TryGetValue(handleId, out var entry))\n        {\n            throw new InvalidOperationException($\"Handle '{handleId}' not found in registry\");\n        }\n        return entry.TypeId;","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.RemoteHost/Ats/HandleRegistry.cs#L80-L116","documentation":"The typed HandleRegistry.GetObject<T> first resolves the handle, then verifies the stored object is assignable to T. If the stored object's type does not match T, it throws this InvalidOperationException naming both the actual and expected type names.","triggerScenarios":"Calling GetObject<T>(handleId) where the handle was registered with an object of a different concrete type — e.g. registering a ProjectResource and retrieving as ContainerResource, or two types sharing a name across assemblies.","commonSituations":"Refactor changed the registered object's type but not retrieval call sites; generic parameter inferred incorrectly; handle IDs collide because IDs were reused for different objects.","solutions":["Use the actual registered type as T (check the error message: it names the stored type).","Register the object under the type you intend to retrieve, or register a second handle for the typed view.","Check for type identity issues: the same FullName from different assembly versions is not T.","Retrieve as object via GetObject(handleId) and pattern-match before casting."],"exampleFix":"// before\nvar project = registry.GetObject<ContainerResource>(handleId); // stored type is ProjectResource\n\n// after\nvar resource = registry.GetObject<ProjectResource>(handleId);","handlingStrategy":"type-guard","validationCode":"var raw = registry.GetObject(handleId);\nif (raw is not MyExpectedType)\n    throw new InvalidOperationException($\"Handle '{handleId}' holds {raw.GetType().FullName}; expected {typeof(MyExpectedType).FullName}.\");","typeGuard":"bool TryGetTyped<T>(Aspire.Hosting.RemoteHost.Ats.HandleRegistry registry, string id, out T? typed) where T : class\n{\n    typed = null;\n    try { typed = registry.GetObject<T>(id); return true; }\n    catch (InvalidOperationException) { return false; }\n}","tryCatchPattern":"try\n{\n    var resource = registry.GetObject<ContainerResource>(handleId);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"contains\") && ex.Message.Contains(\"expected\"))\n{\n    logger.LogError(ex, \"Handle type mismatch: {Message}\", ex.Message);\n}","preventionTips":["Keep a single source of truth mapping handle IDs to their registered types.","After refactoring registered types, update all GetObject<T> call sites together.","Retrieve as object and pattern-match when the concrete type is uncertain.","Register separate handles for distinct typed views instead of reusing IDs."],"tags":["handle-registry","type-mismatch","remote-host"],"backgroundTag":"type-mismatch","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}