microsoft/aspire · error · InvalidOperationException

The MAUI OTLP dev tunnel configuration was not initialized…

Error message

The MAUI OTLP dev tunnel configuration was not initialized before endpoint allocation.

What it means

The ResourceEndpointsAllocatedEvent handler for the MAUI OTLP dev tunnel requires the same deferred tunnelConfig state. If endpoints are allocated before WithOtlpDevTunnel's initialization produced the configuration, the handler throws InvalidOperationException. It mirrors error 1137 but on the endpoint-allocation lifecycle event.

Solutions

  1. Apply WithOtlpDevTunnel during app-model construction (before builder.Build()/Run), never after startup begins.
  2. Confirm the endpoint-allocated resource is the MAUI-managed tunnel and not another resource leaking into the handler.
  3. Avoid manually invoking endpoint allocation or reshaping resource startup order in tests or custom code.
  4. Upgrade Aspire.Hosting.Maui if a known event-ordering race was fixed in a later version.

Example fix

// before
app.Start();
mauiResource.WithOtlpDevTunnel(); // too late: endpoints already allocated
// after
mauiResource.WithOtlpDevTunnel();
app.Start();
Defensive patterns

Strategy: validation

Validate before calling

// ensure tunnel wiring precedes endpoint allocation events
if (endpointsAllocated && !otlpTunnelWired) throw new InvalidOperationException("Apply WithOtlpDevTunnel before endpoints are allocated.");

Try / catch

try { await startAsync(); } catch (InvalidOperationException ex) when (ex.Message.Contains("not initialized before endpoint allocation")) { /* wire WithOtlpDevTunnel earlier; don't force endpoint allocation */ }

Prevention

When it happens

Trigger: ResourceEndpointsAllocatedEvent fires for a resource routed into this handler while tunnelConfig is still null at src/Aspire.Hosting.Maui/MauiOtlpExtensions.cs:194.

Common situations: Event-ordering problems where endpoint allocation precedes tunnel initialization; manually triggering endpoint allocation in tests; wiring WithOtlpDevTunnel after resources have started; multiple tunnels with mismatched names.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/f31d1aa0c66aa0ec. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Maui/MauiOtlpExtensions.cs:194

                    if (dashboardOtlpEndpoint is null)
                    {
                        var exception = new DistributedApplicationException($"The Aspire dashboard resource '{KnownResourceNames.AspireDashboard}' terminated or does not have a concrete OTLP endpoint named '{KnownEndpointNames.OtlpHttpEndpointName}' or '{KnownEndpointNames.OtlpGrpcEndpointName}', so the MAUI OTLP dev tunnel for resource '{parentBuilder.Resource.Name}' cannot start. Ensure dashboard OTLP ingestion is enabled, or configure an explicit OTLP endpoint URL.");
                        if (currentTunnelConfig.TryFailOtlpEndpointResolution(exception))
                        {
                            throw exception;
                        }

                        return;
                    }

                    await AllocateOtlpStubEndpointAsync(currentTunnelConfig, dashboardOtlpEndpoint.Value, evt.Services, appBuilder.Eventing, ct).ConfigureAwait(false);
                }
            });

            appBuilder.Eventing.Subscribe<ResourceEndpointsAllocatedEvent>(async (evt, ct) =>
            {
                var currentTunnelConfig = tunnelConfig ?? throw new InvalidOperationException("The MAUI OTLP dev tunnel configuration was not initialized before endpoint allocation.");
                if (await TryResolveDashboardOtlpEndpointAsync(
                    evt.Resource,
                    evt.Services,
                    waitForRuntimeSnapshot: false,
                    currentTunnelConfig.RuntimeSnapshotResolutionTimeout,
                    ct).ConfigureAwait(false) is { } dashboardOtlpEndpoint)
                {
                    await AllocateOtlpStubEndpointAsync(currentTunnelConfig, dashboardOtlpEndpoint, evt.Services, appBuilder.Eventing, ct).ConfigureAwait(false);
                }
            });
        }
        else
        {
            appBuilder.OnBeforeStart((evt, ct) =>
                appBuilder.Eventing.PublishAsync(new ResourceEndpointsAllocatedEvent(stubResource, evt.Services), ct));
        }

        // Create dev tunnel with anonymous access for OTLP. The dynamic unresolved-endpoint guard above

View on GitHub (pinned to 25830f84bd)