Sonarr/Sonarr · error · Error
Failed to restore backup: ${response.statusText}
Error message
Failed to restore backup: ${response.statusText} What it means
Thrown by the base REST controller's ValidateId guard whenever a resource ID is <= 0. Sonarr identifies every resource with a positive integer; zero and negative values are not real records and signal a malformed or uninitialized request. ValidateId is inherited by all REST resource controllers, so this guard protects every /api/{resource}/{id} route that calls it.
Source
Thrown at frontend/src/System/Backup/useBackups.ts:92
Error,
FormData
>({
mutationFn: async (formData: FormData) => {
const response = await fetch(
`${window.Sonarr.urlBase}/api/v5/system/backup/restore/upload`,
{
method: 'POST',
headers: {
'X-Api-Key': window.Sonarr.apiKey,
'X-Sonarr-Client': 'Sonarr',
// Don't set Content-Type, let browser set it with boundary for multipart/form-data
},
body: formData,
}
);
if (!response.ok) {
throw new Error(`Failed to restore backup: ${response.statusText}`);
}
return response.json();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['/system/backup'] });
},
});
return {
uploadBackup: mutate,
isUploadingBackup: isPending,
uploadBackupError: error,
};
};
View on GitHub (pinned to da2284d7ea)
Solutions
- Make sure the id originates from a successful prior create or list response and is a positive integer before issuing the request.
- Validate id > 0 client-side and short-circuit (or surface a clear error) before constructing the URL.
- Inspect URL construction for placeholder/template bugs that can produce /resource/0 or /resource/-1.
- If the id came from a lookup that returned nothing, fix the upstream lookup rather than forwarding its default value.
- Log the raw id value at the call site to confirm whether the problem is the source of the id or URL parsing.
Example fix
// before
// await client.DeleteSeriesAsync(seriesId); // seriesId == 0 (uninitialized)
//
// after
// if (seriesId <= 0) throw new ArgumentException("seriesId must be set", nameof(seriesId));
// await client.DeleteSeriesAsync(seriesId); Defensive patterns
Strategy: validation
Validate before calling
// Validate before any REST call that takes a resource id.
static void EnsureValidId(int id, [CallerArgumentExpression(nameof(id))] string? name = null)
{
if (id <= 0)
throw new ArgumentOutOfRangeException(name, id, "Resource id must be a positive integer.");
}
// usage
EnsureValidId(seriesId);
await client.GetSeriesAsync(seriesId, ct); Type guard
// Narrow/validate an id value sourced from untyped data (JSON, query) before use.
static bool IsValidResourceId(object? value, out int id) =>
value is int i && i > 0 && (id = i) == i;
// usage: if (!IsValidResourceId(payload["id"], out var id)) return; Try / catch
try
{
await client.UpdateSeriesAsync(id, resource, ct);
}
catch (ApiException ex) when (ex.StatusCode == HttpStatusCode.BadRequest &&
ex.Message.Contains("is not a valid ID"))
{
// id was <= 0; treat as a programming error, not a transient failure.
throw new InvalidOperationException($"Refusing to retry: id={id} is non-positive. Fix the id source.", ex);
} Prevention
- Treat a non-positive id as a programmer error: fail loud at the call boundary rather than letting it reach the server.
- Always source ids from successful create/list responses; never reuse an id after the lookup that produced it failed.
- Unit-test URL/template builders with an unset-id case to catch /resource/0 before runtime.
- Centralize REST id handling in one client method that applies the > 0 guard so it cannot be skipped.
When it happens
Trigger: Any GET/PUT/DELETE (or resource read/modify) against a REST resource endpoint where the {id} resolves to 0 or a negative number; a route where the id segment fails to bind and defaults to 0; a client building the URL from an unset variable; an action that chains ValidateId on an id sourced from an empty collection or failed lookup.
Common situations: Client code that uses an uninitialized/default int id (0) before it has been populated from a create/list call; deleting or updating a resource whose id was never fetched; URL templating that leaves a placeholder unsubstituted (e.g. /series/0); off-by-one after treating a list index as the resource id; chained calls where a previous step returned no item but its (default) id was passed forward.
Related errors
- No OAuth URL received from intermediate request
- Request Error: (${statusCode}) ${path}
- CustomFormatUnknownCondition
- CustomFormatUnknownConditionOption
- File {0} failed archive validation.
AI-assisted analysis of Sonarr/Sonarr@da2284d7ea (2026-08-13).
Data as JSON: /api/errors/04b7cc9b965ea15d.
Report an issue: GitHub.