{"record":{"id":"f15660b3e6a429b6","repo":"microsoft/aspire","slug":"the-maui-otlp-dev-tunnel-configuration-was-not-initialized","errorCode":null,"errorMessage":"The MAUI OTLP dev tunnel configuration was not initialized before tunnel startup.","messagePattern":"The MAUI OTLP dev tunnel configuration was not initialized before tunnel startup\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Maui/MauiOtlpExtensions.cs","lineNumber":132,"sourceCode":"\n        var stubBuilder = appBuilder.AddResource(stubResource)\n            .ExcludeFromManifest();\n\n        // Hide the stub from the dashboard UI\n        stubBuilder.WithHidden().WithInitialState(new CustomResourceSnapshot\n        {\n            ResourceType = \"OtlpStub\",\n            Properties = []\n        });\n\n        if (configuredOtlpEndpoint is null)\n        {\n            appBuilder.Eventing.Subscribe<BeforeResourceStartedEvent>(async (evt, ct) =>\n            {\n                if (evt.Resource is DevTunnelResource devTunnelResource &&\n                    string.Equals(devTunnelResource.Name, tunnelName, StringComparisons.ResourceName))\n                {\n                    var currentTunnelConfig = tunnelConfig ?? throw new InvalidOperationException(\"The MAUI OTLP dev tunnel configuration was not initialized before tunnel startup.\");\n                    if (currentTunnelConfig.IsOtlpEndpointResolved)\n                    {\n                        return;\n                    }\n\n                    var dashboardResource = appBuilder.Resources.FirstOrDefault(resource =>\n                        string.Equals(resource.Name, KnownResourceNames.AspireDashboard, StringComparisons.ResourceName));\n                    if (dashboardResource is null)\n                    {\n                        var exception = new DistributedApplicationException($\"The MAUI OTLP dev tunnel for resource '{parentBuilder.Resource.Name}' requires the Aspire dashboard to be enabled or an explicit OTLP endpoint URL to be configured.\");\n                        if (currentTunnelConfig.TryFailOtlpEndpointResolution(exception))\n                        {\n                            throw exception;\n                        }\n\n                        return;\n                    }\n","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Maui/MauiOtlpExtensions.cs#L114-L150","documentation":"WithOtlpDevTunnel defers tunnel setup via closures that capture a tunnelConfig reference initialized later. If the BeforeResourceStartedEvent handler for the dev tunnel fires while tunnelConfig is still null, the captured state was never initialized, so the subscriber throws InvalidOperationException rather than configuring a tunnel blindly.","triggerScenarios":"The BeforeResourceStartedEvent for the DevTunnelResource named tunnelName fires before WithOtlpDevTunnel's initialization path ran (tunnelConfig still null) at src/Aspire.Hosting.Maui/MauiOtlpExtensions.cs:132.","commonSituations":"Starting the dev tunnel resource before the MAUI OTLP wiring completes; calling WithOtlpDevTunnel on the wrong resource or after the app model started; event ordering changes across Aspire versions; manually starting the tunnel resource in tests.","solutions":["Ensure WithOtlpDevTunnel is applied to the MAUI resource before the AppHost starts, so initialization runs before the tunnel's BeforeResourceStartedEvent.","Verify the tunnel resource name matches the one created by WithOtlpDevTunnel (tunnelName) — starting a foreign tunnel resource triggers the guard.","Don't manually start or reorder the DevTunnelResource; let the MAUI extension manage its lifecycle.","If reproducing in tests, wait for model construction to finish before triggering resource-start events."],"exampleFix":"// before\nvar maui = builder.AddMauiProject(...);\nbuilder.AddDevTunnel(\"otlp-tunnel\").WithOtlpDevTunnel(maui); // tunnel created separately, wrong order\n// after\nmaui.WithOtlpDevTunnel(); // extension creates and wires the tunnel itself","handlingStrategy":"validation","validationCode":"// assert wiring happens before start\nif (appModelBuilt) throw new InvalidOperationException(\"WithOtlpDevTunnel must be applied before builder.Build()/Run().\");","typeGuard":null,"tryCatchPattern":"try { await startAsync(); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"tunnel configuration was not initialized\")) { /* move WithOtlpDevTunnel earlier in app-model construction */ }","preventionTips":["Call WithOtlpDevTunnel during model construction, before Build/Run","Let the extension create and own the DevTunnelResource — don't hand-roll one","Don't manually start tunnel resources or reorder start events","Keep MAUI hosting packages at consistent versions"],"tags":["maui","otlp","dev-tunnel","lifecycle","race-condition"],"backgroundTag":"invalid-state-transition","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}