dotnet/orleans · warning · RequestFailedException
Resource not found
Error message
Resource not found
What it means
Thrown by AzureTableDataManager.DeleteTableEntryAsync when Table.DeleteEntityAsync returns HTTP 404 — the entity did not exist at delete time. The code synthesizes an Azure.RequestFailedException(status 404, 'Resource not found') so callers see a consistent exception for a missing resource. Semantically this is an idempotent-delete miss: the row is already gone.
Source
Thrown at src/Azure/Shared/Storage/AzureTableDataManager.cs:355
/// Fails if the data does not already exist or if eTag does not match.
/// </summary>
/// <param name="data">Data entry to be deleted from the table.</param>
/// <param name="eTag">ETag to use.</param>
/// <returns>Completion promise for this storage operation.</returns>
public async Task DeleteTableEntryAsync(T data, ETag eTag)
{
const string operation = "DeleteTableEntryAsync";
var startTime = DateTime.UtcNow;
LogTraceTableEntry(Logger, operation, data, TableName);
try
{
data.ETag = eTag;
try
{
var response = await Table.DeleteEntityAsync(data.PartitionKey, data.RowKey, data.ETag);
if (response is { Status: 404 })
{
throw new RequestFailedException(response.Status, "Resource not found", response.ReasonPhrase, null);
}
}
catch (Exception exc)
{
LogWarningDeleteTableEntry(Logger, exc, data, TableName);
throw;
}
}
finally
{
CheckAlertSlowAccess(startTime, operation);
}
}
/// <summary>
/// Read a single table entry from the storage table.
/// </summary>
/// <param name="partitionKey">The partition key for the entry.</param>View on GitHub (pinned to fca799fa70)
Solutions
- Treat 404 on delete as success (idempotent) by catching RequestFailedException where Status == 404.
- If strict existence is required, read-before-delete and handle the not-found case explicitly.
- Coordinate concurrent deleters so they do not target the same partition/row key.
Example fix
// before
try { await manager.DeleteTableEntryAsync(entity, etag); }
catch (Exception) { throw; } // 404 propagates and fails the caller
// after
try { await manager.DeleteTableEntryAsync(entity, etag); }
catch (RequestFailedException ex) when (ex.Status == 404) { /* already deleted: idempotent success */ } Defensive patterns
Strategy: try-catch
Type guard
static bool IsNotFound(RequestFailedException ex) => ex.Status == 404;
Try / catch
try { await manager.DeleteTableEntryAsync(entity, etag); }
catch (RequestFailedException ex) when (ex.Status == 404) { /* already deleted: treat as success */ } Prevention
- Treat 404 on delete as idempotent success.
- Coordinate concurrent deleters to avoid races.
- Read-before-delete only if strict existence is required.
When it happens
Trigger: Deleting a table entity that was already deleted, expired, or never inserted; concurrent deleters racing on the same partition/row key; replay after a prior successful delete.
Common situations: Grain deactivation racing with another deleter; eventual-consistency replay; cleanup logic running twice; reminders/storage cleanup after data was purged out-of-band.
Related errors
- Could not find table version row or found too many entries.
- Did not read table version row. Read = {0}
- Value cannot be null. (Parameter 'createClientCallback')
- Value cannot be null. (Parameter 'connectionString')
- Value cannot be null. (Parameter 'serviceUri')
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/06a6117c5d266d3a.
Report an issue: GitHub.