microsoft/aspire · error · ArgumentException
Anonymous volumes cannot be read-only.
Error message
Anonymous volumes cannot be read-only.
What it means
An anonymous volume (a Volume mount with no source) is created by the runtime with an unpredictable name, so making it read-only is meaningless and almost certainly a mistake — there is no stable source to protect. When type is Volume, source is null/empty, and isReadOnly is true, the constructor throws ArgumentException on the isReadOnly parameter.
Solutions
- Set isReadOnly: false for anonymous volumes.
- Provide an explicit source path if the volume must be read-only.
- If it was meant to be a bind mount, switch the type back to BindMount and supply the absolute host path.
Example fix
// before var mount = new ContainerMountAnnotation(null, "/cache", ContainerMountType.Volume, isReadOnly: true); // after var mount = new ContainerMountAnnotation(null, "/cache", ContainerMountType.Volume, isReadOnly: false);
Defensive patterns
Strategy: validation
Validate before calling
if (type == ContainerMountType.Volume && string.IsNullOrEmpty(source) && isReadOnly)
throw new ArgumentException("Anonymous volumes cannot be read-only.", nameof(isReadOnly)); Try / catch
try
{
var mount = new ContainerMountAnnotation(source, target, type, isReadOnly);
}
catch (ArgumentException ex) when (ex.ParamName == nameof(isReadOnly))
{
logger.LogWarning("Anonymous volume at {Target} cannot be read-only; falling back to read-write", target);
var mount = new ContainerMountAnnotation(source, target, type, isReadOnly: false);
} Prevention
- Only set isReadOnly: true when a concrete source path is supplied.
- Default isReadOnly to false for volume mounts in helper methods.
- Tie the readonly flag to the presence of a source in config-driven mount builders.
- Add a unit test asserting anonymous+readonly is rejected.
When it happens
Trigger: new ContainerMountAnnotation(null, "/data", ContainerMountType.Volume, isReadOnly: true) — declaring an anonymous volume and marking it read-only in the same call.
Common situations: Copy-pasting a bind-mount line, changing the type to Volume, but leaving isReadOnly: true; generating mounts from configuration where readonly is defaulted to true and the source was omitted; attempting to make a container-writable scratch location immutable.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Bind mounts must specify a source path.
- Bind mounts must specify an absolute path.
- AllocatedEndpoint must use the same network as the…
- Cannot set both UseDeveloperCertificate and Certificate…
- Command array cannot be empty.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/aa90139bcdda4740.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting/ApplicationModel/ContainerMountAnnotation.cs:39
/// <param name="isReadOnly">A value indicating whether the mount is read-only.</param>
public ContainerMountAnnotation(string? source, string target, ContainerMountType type, bool isReadOnly)
{
if (type == ContainerMountType.BindMount)
{
if (string.IsNullOrEmpty(source))
{
throw new ArgumentNullException(nameof(source), MessageStrings.ContainerMountBindMountsRequireSourceExceptionMessage);
}
if (!Path.IsPathRooted(source))
{
throw new ArgumentException(MessageStrings.ContainerMountBindMountsRequireRootedPaths, nameof(source));
}
}
if (type == ContainerMountType.Volume && string.IsNullOrEmpty(source) && isReadOnly)
{
throw new ArgumentException(MessageStrings.ContainerMountAnonymousVolumesReadOnlyExceptionMessage, nameof(isReadOnly));
}
Source = source;
Target = target;
Type = type;
IsReadOnly = isReadOnly;
}
/// <summary>
/// Gets the source of the bind mount or name if a volume. Can be <c>null</c> if the mount is an anonymous volume.
/// </summary>
public string? Source { get; }
/// <summary>
/// Gets the target of the mount.
/// </summary>
public string Target { get; }
View on GitHub (pinned to 25830f84bd)