{"record":{"id":"67ba242be0922532","repo":"microsoft/aspire","slug":"client-must-authenticate-before-invoking-apphost-rpc-methods","errorCode":null,"errorMessage":"Client must authenticate before invoking AppHost RPC methods.","messagePattern":"Client must authenticate before invoking AppHost RPC methods\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.RemoteHost/JsonRpcAuthenticationState.cs","lineNumber":67,"sourceCode":"\n            if (isMatch)\n            {\n                IsAuthenticated = true;\n            }\n\n            return isMatch;\n        }\n        finally\n        {\n            CryptographicOperations.ZeroMemory(providedTokenBytes);\n        }\n    }\n\n    public void ThrowIfNotAuthenticated()\n    {\n        if (!IsAuthenticated)\n        {\n            throw new InvalidOperationException(\"Client must authenticate before invoking AppHost RPC methods.\");\n        }\n    }\n}\n","sourceCodeStart":49,"sourceCodeEnd":71,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.RemoteHost/JsonRpcAuthenticationState.cs#L49-L71","documentation":"Aspire.Hosting.RemoteHost exposes AppHost functionality over JSON-RPC, and every RPC entry point calls ThrowIfNotAuthenticated to gate access. This InvalidOperationException is thrown when a client invokes an RPC method (directly or via LanguageService) before completing the authentication handshake. The server rejects the call rather than executing unauthenticated work.","triggerScenarios":"Calling any AppHost RPC method (e.g. scaffoldAppHost, getRuntimeSpec) over the JsonRpc connection without first sending the authentication message that sets JsonRpcAuthenticationState.IsAuthenticated to true.","commonSituations":"Custom or hand-rolled clients connecting to the remote host pipe/socket without performing the handshake; a client that lost its auth token or connected with a stale protocol; tooling that reconnects after a server restart but skips re-authentication; misordered startup where RPC calls are issued before auth completes.","solutions":["Complete the authentication handshake before invoking any RPC method (send the auth message/token the server expects and wait for success).","If using a provided client API, ensure it is initialized/connected through its normal entry point rather than binding JsonRpc manually.","On reconnect (after server restart or transport drop), re-run the authentication step before resuming RPC calls.","Check server logs to confirm your client identity/token was accepted; fix the credential if authentication silently failed."],"exampleFix":"// before\nvar rpc = JsonRpc.Attach(stream);\nawait rpc.InvokeAsync(\"scaffoldAppHost\", \"dotnet\", path, name);\n\n// after\nvar rpc = JsonRpc.Attach(stream);\nawait AuthenticateAsync(rpc); // perform handshake first\nawait rpc.InvokeAsync(\"scaffoldAppHost\", \"dotnet\", path, name);","handlingStrategy":"validation","validationCode":"// Before invoking any RPC, check auth state if exposed, or track it client-side:\nif (!authHandshakeCompleted)\n    throw new InvalidOperationException(\"Complete authentication before RPC calls.\");","typeGuard":null,"tryCatchPattern":"try { await rpc.InvokeAsync(\"scaffoldAppHost\", ...); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"authenticate\"))\n{ /* re-authenticate then retry */ }","preventionTips":["Always run the auth handshake immediately after attaching the JsonRpc connection.","Centralize connection setup in one helper so RPC calls cannot be issued pre-auth.","Re-authenticate on every reconnect; never cache an assumed-authenticated state across sessions."],"tags":["json-rpc","authentication","aspire-hosting"],"backgroundTag":"authentication-required","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"}