{"record":{"id":"6d900040506fd683","repo":"microsoft/aspire","slug":"infra-is-not-set","errorCode":null,"errorMessage":"Infra is not set","messagePattern":"Infra is not set","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Azure.AppService/AzureAppServiceWebsiteContext.cs","lineNumber":35,"sourceCode":"internal sealed class AzureAppServiceWebsiteContext(\n    IResource resource,\n    AzureAppServiceEnvironmentContext environmentContext)\n{\n    public IResource Resource => resource;\n\n    record struct EndpointMapping(string Scheme, BicepValue<string> Host, int Port, int? TargetPort, bool IsHttpIngress, bool External);\n\n    private readonly Dictionary<string, EndpointMapping> _endpointMapping = [];\n    private readonly Dictionary<string, EndpointMapping> _slotEndpointMapping = [];\n\n    // Resolved environment variables and command line args\n    // These contain the values that need to be further transformed into\n    // bicep compatible values\n    public Dictionary<string, object> EnvironmentVariables { get; } = [];\n    public List<object> Args { get; } = [];\n\n    private AzureResourceInfrastructure? _infrastructure;\n    public AzureResourceInfrastructure Infra => _infrastructure ?? throw new InvalidOperationException(\"Infra is not set\");\n\n    // Naming the app service is globally unique (domain names), so we use the resource group ID to create a unique name\n    // within the naming spec for the app service.\n    private BicepValue<string> HostName => BicepFunction.Take(\n        BicepFunction.Interpolate($\"{BicepFunction.ToLower(resource.Name)}-{AzureAppServiceEnvironmentResource.GetWebSiteSuffixBicep()}\"), 60);\n\n    /// <summary>\n    /// Gets the hostname for a deployment slot by appending the slot name to the base website name.\n    /// </summary>\n    /// <param name=\"deploymentSlot\">The deployment slot name.</param>\n    /// <returns>A <see cref=\"BicepValue{T}\"/> representing the slot hostname, truncated to the maximum allowed length.</returns>\n    public BicepValue<string> GetSlotHostName(BicepValue<string> deploymentSlot)\n    {\n        var websitePrefix = BicepFunction.Take(\n            BicepFunction.Interpolate($\"{BicepFunction.ToLower(resource.Name)}-{AzureAppServiceEnvironmentResource.GetWebSiteSuffixBicep()}\"), AzureAppServiceWebSiteResource.MaxWebSiteNamePrefixLengthWithSlot);\n\n        return BicepFunction.Take(\n            BicepFunction.Interpolate($\"{websitePrefix}-{BicepFunction.ToLower(deploymentSlot)}\"), AzureAppServiceWebSiteResource.MaxHostPrefixLengthWithSlot);","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.AppService/AzureAppServiceWebsiteContext.cs#L17-L53","documentation":"AzureAppServiceWebsiteContext lazily caches its AzureResourceInfrastructure in _infrastructure; the Infra property throws this InvalidOperationException when accessed before BuildWebSite (or an equivalent method) has assigned it. Infra is only valid while the website is being built into an AzureResourceInfrastructure, so any use outside that phase is a programming/lifecycle error.","triggerScenarios":"Accessing the Infra property (directly, or indirectly through helpers like AllocateKeyVaultSecretUriReference, AllocateParameter, or BicepValue resolution that need Infra) before AzureAppServiceWebsiteContext.BuildWebSite has been called with an AzureResourceInfrastructure.","commonSituations":"Custom annotations or callbacks (e.g. AzureAppServiceWebsiteCustomizationAnnotation) that inspect the website context too early; calling context methods during resource modeling instead of during publish/infrastructure generation; tests instantiating the context and poking at Infra without running the build phase.","solutions":["Ensure the website context's BuildWebSite(infra) runs before any code touches Infra — hook custom logic into the infrastructure-building phase, not resource-modeling phase.","Move annotation callbacks so they execute after the context's _infrastructure is assigned (BuildWebSite sets it).","In tests or tooling, call BuildWebSite with a real AzureResourceInfrastructure before asserting on Infra-dependent values."],"exampleFix":"// before (annotation running too early, Infra not yet set)\nvar infra = websiteContext.Infra; // throws\n// after\nenvironmentContext.BuildWebSite(infra); // assigns Infra\nvar value = websiteContext.Infra;","handlingStrategy":"validation","validationCode":"if (websiteContext.InfraExists /* or track via BuildWebSite having run */) { useInfra(); } else { throw new InvalidOperationException(\"BuildWebSite must run before accessing Infra\"); }","typeGuard":"bool InfraIsInitialized(AzureAppServiceWebsiteContext ctx) => ctx.GetType().GetField(\"_infrastructure\", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(ctx) is not null;","tryCatchPattern":"try { var infra = ctx.Infra; }\ncatch (InvalidOperationException ex) when (ex.Message == \"Infra is not set\")\n{\n    throw new InvalidOperationException(\"Access websiteContext.Infra only inside the publish/build phase (after BuildWebSite).\", ex);\n}","preventionTips":["Only access Infra from code that runs during infrastructure generation (BuildWebSite, annotations invoked at publish time).","Never read Infra during resource modeling in the AppHost.","In tests, call BuildWebSite(infra) before asserting on Infra-dependent outputs."],"tags":["azure-app-service","lifecycle","null-state","publishing"],"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-21T04:17:39.646Z"}