Table of Contents

Errors

Resourcefull reports an expected absence with a return value and everything else with an exception.

Situation Result
A single resource, version or container that doesn't exist null
A listing with nothing in it an empty list, never null
An existence check, or a delete of something that may not exist (…IfExistsAsync) bool
A null name, or a missing argument ArgumentNullException, before storage is contacted
A name that breaks the name rules ResourceNameException, an ArgumentException, before storage is contacted
Uploading a name that exists, when the upload is create-only ResourceConflictException
Creating a container that exists ResourceConflictException
Uploading into a container that doesn't exist ResourceContainerNotFoundException
An upload or delete whose ResourceConditions the current version doesn't meet, including a delete with conditions of a name that doesn't exist ResourcePreconditionFailedException (nothing changes)
Moving a resource onto a name that exists, or importing into a container that exists 4.0 ResourceConflictException
A download range that starts past the end of the content 4.0 ResourceRangeNotSatisfiableException, with the content's length
A download range with a negative offset or length 4.0 ArgumentOutOfRangeException
A version deleted while it's being downloaded, with SQL Server IOException from the download stream, rather than a stream that ends early
Importing a file that isn't an export, describes something that can't be imported, or whose content was changed 4.0 InvalidDataException (nothing is left behind)
Importing from a stream that can't seek 4.0 ArgumentException
An import that fails, and then fails to delete what it imported 4.0 AggregateException, holding both failures
A feature the storage provider doesn't support, such as a provider written for an earlier release NotSupportedException
An upload whose declared length differs from its content ResourceContentLengthMismatchException (nothing is stored)
A write that breaks its container's policy 4.0 ResourcePolicyViolationException (nothing changes)
An upload or imported version your upload inspector refuses 4.0 ResourceContentRefusedException, with the inspector's reason (nothing is stored)
An upload inspector that throws 4.0 the inspector's exception (nothing is stored)
UseVersioning with fewer than one version ArgumentOutOfRangeException
Configuring no provider, or two InvalidOperationException from AddResourcefull
A canceled operation OperationCanceledException
A storage failure the provider's exception, such as SqlException; with SQL Server, a transient failure that outlasts the retries throws EF Core's RetryLimitExceededException, with the last failure as its inner exception

Reading from a container that doesn't exist

Writing into a container that doesn't exist throws ResourceContainerNotFoundException, but reading from it and deleting from it treat it as an empty container: listings are empty, GetUsageAsync 4.0 reports zero, downloads and GetResourceInfoAsync return null, and ExistsAsync and …IfExistsAsync deletes return false. So a misspelled container name looks like an empty container rather than an error. Where that matters, such as a container name that comes from a request, check the service client's ContainerExistsAsync first and answer 404 if it's false:

if (!await resources.ContainerExistsAsync(name, cancellationToken)) return Results.NotFound();
IResourceContainerClient container = resources.GetContainerClient(name);

Resourcefull's exceptions

All of them derive from ResourcefullException, so one catch handles any of them:

Exception Meaning HTTP status it usually maps to
ResourceConflictException The name or container already exists. 409 Conflict
ResourceContainerNotFoundException The container was never created, or was deleted before the write. 404 Not Found
ResourceContentLengthMismatchException The upload's declared length didn't match its content. 400 Bad Request
ResourcePreconditionFailedException The name's current version didn't meet the upload's or delete's conditions. 412 Precondition Failed
ResourcePolicyViolationException 4.0 The write broke its container's policy; Rule says which rule, and Limit its limit. 413 for the size limits, 409 for MaxResourceCount, 403 for ReadOnly, 415 for AllowedContentTypes
ResourceRangeNotSatisfiableException 4.0 The download range starts past the end of the content; ContentLength says how long it is. 416 Range Not Satisfiable
ResourceContentRefusedException 4.0 The upload inspector refused the content; Reason says why. 422 Unprocessable Content
ResourceUploadOffsetException 4.0 An append to an upload session didn't start where its stored content ends; CurrentOffset says where to resume. 409 Conflict
ResourceRetainedException 4.0 A delete would remove a version that's retained or under a legal hold; VersionId, RetainUntil and LegalHold say which and why. Nothing was deleted, unless the version was protected while a batched delete was under way. 409 Conflict
ResourceUploadInterruptedException 4.0 An upload's version was deleted before the upload completed, by a container delete running at the same time or by the sweep that removes uploads that have stored nothing for a day. Nothing was stored; try again, though if the container was deleted, the retry throws ResourceContainerNotFoundException. 409 Conflict
ResourceUploadLimitException 4.0 An append would take an upload session past what its provider can store in one session, or an upload is larger than its provider can store in one object. 413 Content Too Large

ResourceNameException derives from ArgumentException rather than ResourcefullException, so existing catch (ArgumentException) code still catches it; it maps to 400 Bad Request. Its Name 4.0 is the name that broke the rules.

What an exception is about

ContainerName and ResourceName 4.0 say what a ResourcefullException is about, so you don't have to read its message:

  • A resource: both are set. For a copy or move whose destination is the problem, such as a destination name that exists, they name the destination.
  • A container: only ContainerName is set, as for creating a container that exists, or for a ResourcePolicyViolationException, which names the container whose policy refused the write.

They're set whatever the storage provider: when a provider doesn't set them, the client fills them in from the call that failed. They aren't sent in HTTP responses or recorded in telemetry, so a resource name in them stays within your application.

try
{
    await container.UploadAsync(name, content);
}
catch (ResourceConflictException)
{
    // someone else stored this name first
}
catch (ResourceContainerNotFoundException)
{
    // create the container, or report it missing
}

The ASP.NET Core package maps them all, the name exception included, to responses in one place.