{"record":{"id":"8b9141664dd00579","repo":"microsoft/aspire","slug":"volume-volumename-on-resource-context-resource-name-does-not","errorCode":null,"errorMessage":"Volume '{VolumeName}' on resource '{context.Resource.Name}' does not declare a mount path.","messagePattern":"Volume '(.+?)' on resource '(.+?)' does not declare a mount path\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/ApplicationModel/VolumeMountBindingAnnotation.cs","lineNumber":83,"sourceCode":"\n    /// <summary>\n    /// Resolves the storage path the workload should use for the current execution mode.\n    /// </summary>\n    /// <param name=\"context\">The environment callback context being evaluated.</param>\n    /// <returns>\n    /// <see cref=\"MountPath\"/> when publishing or when the workload runs as a container, and otherwise a\n    /// local host directory.\n    /// </returns>\n    /// <exception cref=\"InvalidOperationException\">\n    /// Thrown when the deployed mount path is required but this binding does not declare one.\n    /// </exception>\n    public string ResolvePath(EnvironmentCallbackContext context)\n    {\n        ArgumentNullException.ThrowIfNull(context);\n\n        if (context.ExecutionContext.IsPublishMode || context.Resource is ContainerResource)\n        {\n            var mountPath = MountPath ?? throw new InvalidOperationException(\n                $\"Volume '{VolumeName}' on resource '{context.Resource.Name}' does not declare a mount path.\");\n\n            if (context.ExecutionContext.IsPublishMode)\n            {\n                ThrowIfEnvironmentCannotMount(context);\n            }\n\n            return mountPath;\n        }\n\n        // Prefer this binding's own resolver. The sibling scan below only exists for the name-match\n        // composition, where the mount and the compute environment binding are spelled as two separate\n        // calls and the mount-declaring annotation therefore carries no resolver of its own.\n        //\n        // Scanning unconditionally would alias distinct volumes, because VolumeName is not a unique key —\n        // two compute environments can each declare a volume under the same name, and every binding would\n        // then select the last resolver and point at one environment's store. Aspire.Hosting.Kubernetes\n        // rejects that shape up front, but this annotation is public and shared across compute","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/ApplicationModel/VolumeMountBindingAnnotation.cs#L65-L101","documentation":"VolumeMountBindingAnnotation.ResolvePath computes the path a volume mount is exposed at. In publish mode or for ContainerResource, the MountPath must be declared; if VolumeName is set but MountPath is null, ResolvePath throws InvalidOperationException stating the volume does not declare a mount path. Without a mount path the host cannot know where inside the container/compute the volume should be attached.","triggerScenarios":"Calling WithVolume/WithPersistentVolume-style APIs (WithPersistentVolumeCore/WithVolumeCore call ResolvePath) where the volume annotation has a VolumeName but no MountPath, in publish mode or on a container resource.","commonSituations":"Using WithVolume(name) overload without specifying the container mount path when targeting containers or publish; refactoring from run-mode-only volume usage into containerized/published scenarios where MountPath becomes mandatory; copying volume config from a project resource to a container resource.","solutions":["Specify the mount path when adding the volume, e.g. WithVolume(\"mydata\", \"/data\") instead of WithVolume(\"mydata\").","For project resources only running locally in run mode, confirm you are not accidentally in publish mode where MountPath is required.","If you own the annotation construction, set the MountPath property on the VolumeMountAnnotation before resolution."],"exampleFix":"// before\nvar pg = builder.AddPostgres(\"pg\").WithDataVolume(\"pgdata\"); // no mount path\n\n// after\nvar pg = builder.AddPostgres(\"pg\")\n    .WithVolume(\"pgdata\", \"/var/lib/postgresql/data\");","handlingStrategy":"validation","validationCode":"// Ensure every volume annotation has a mount path before publish/container run:\nif (volumeAnnotation.MountPath is null && (context.ExecutionContext.IsPublishMode || resource is ContainerResource))\n    throw new InvalidOperationException($\"Volume '{volumeAnnotation.VolumeName}' needs an explicit mount path.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    var path = volumeMountAnnotation.ResolvePath(context);\n}\ncatch (InvalidOperationException ex)\n{\n    logger.LogError(ex, \"Volume mount path missing: {Message}\", ex.Message);\n}","preventionTips":["Always pass an explicit mount path to WithVolume/WithDataVolume when the resource runs as a container or will be published.","Audit volume usage when switching a project resource to containerized or publish scenarios.","Use the WithVolume(name, mountPath) overload rather than the name-only overload for containers."],"tags":["volume","mount-path","containers","publish-mode"],"backgroundTag":"missing-required-config-field","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"}