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

  1. Make sure the id originates from a successful prior create or list response and is a positive integer before issuing the request.
  2. Validate id > 0 client-side and short-circuit (or surface a clear error) before constructing the URL.
  3. Inspect URL construction for placeholder/template bugs that can produce /resource/0 or /resource/-1.
  4. If the id came from a lookup that returned nothing, fix the upstream lookup rather than forwarding its default value.
  5. 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

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


AI-assisted analysis of Sonarr/Sonarr@da2284d7ea (2026-08-13). Data as JSON: /api/errors/04b7cc9b965ea15d. Report an issue: GitHub.