prometheus/prometheus · error · Error

body.error || res.statusText

Error message

body.error || res.statusText

What it means

In the mantine-ui TSDB status page, POSTing to /api/v1/admin/tsdb/delete_series failed with a JSON body; the error message is the server's body.error if present, else the statusText. delete_series is the admin API for dropping series and fails on invalid matchers, parse errors, or when admin APIs are disabled.

Source

Thrown at web/ui/mantine-ui/src/pages/TSDBStatusPage.tsx:120

    }
    if (endTime !== null) {
      params.append("end", (endTime / 1000).toString());
    }

    setDeleting(true);
    try {
      const res = await fetch(
        `${pathPrefix}/${API_PATH}/admin/tsdb/delete_series?${params.toString()}`,
        {
          method: "POST",
          credentials: "same-origin",
        }
      );

      if (!res.ok) {
        if (res.headers.get("content-type")?.startsWith("application/json")) {
          const body = await res.json();
          throw new Error(body.error || res.statusText);
        }
        throw new Error(res.statusText);
      }

      setDeleteSuccess(
        `Successfully deleted series matching: ${matchList.join(", ")}`
      );
      setMatchers("");
      setStartTime(null);
      setEndTime(null);
    } catch (err) {
      setDeleteError(err instanceof Error ? err.message : "Unknown error");
    } finally {
      setDeleting(false);
    }
  };

  const handleCleanTombstones = async () => {

View on GitHub (pinned to 44d6a0e0b1)

Solutions

  1. Start Prometheus with --web.enable-admin-api to enable delete_series.
  2. Fix matcher syntax (must be a valid PromQL selector, e.g. {job="x"}).
  3. Ensure start/end times fall within existing data and are not equal/empty in invalid ways.
  4. Read body.error in the shown message for the exact server reason.

Example fix

# before
prometheus --config.file=prometheus.yml

# after (enable the admin API this page needs)
prometheus --config.file=prometheus.yml --web.enable-admin-api
Defensive patterns

Strategy: validation

Validate before calling

function validMatchers(m: string): boolean {
  try {
    // reuse prometheus regexp/label syntax check, minimally: non-empty, balanced braces
    return m.trim().length > 0 && (m.match(/{/g) ?? []).length === (m.match(/}/g) ?? []).length;
  } catch {
    return false;
  }
}

Type guard

function isJSONErrorBody(body: unknown): body is { error: string } {
  return typeof (body as any)?.error === 'string';
}

Try / catch

catch (err) {
  if (err instanceof Error) {
    setDeleteError(err.message); // body.error carries the exact server reason
    if (err.message.includes('admin APIs disabled')) promptEnableAdminApi();
  }
}

Prevention

When it happens

Trigger: Invalid matcher syntax in the match field, start/end outside retained data bounds, or the admin API disabled — the server responds 400/501/503 with {"status":"error","error":"..."}.

Common situations: --web.enable-admin-api not passed to Prometheus (admin APIs off by default); malformed matchers like '{foo' or empty match; timestamps outside the retention window.

Related errors


AI-assisted analysis of prometheus/prometheus@44d6a0e0b1 (2026-08-15). Data as JSON: /api/errors/7903399422129b24. Report an issue: GitHub.