decolua/9router · error · Error

Failed to save mappings

Error message

Failed to save mappings

What it means

AntigravityToolCard's handleSaveMappings throws this generic message when the POST to the cli-tools mappings API returns a non-2xx response and the response body carries no specific `error` field. It is a client-side fallback message surfaced in the card's message banner; the real cause is whatever the server rejected the save with (auth failure, invalid model name, backend write error).

Source

Thrown at src/app/(dashboard)/dashboard/cli-tools/components/AntigravityToolCard.js:215

      ...prev,
      [alias]: value,
    }));
  };

  const handleSaveMappings = async () => {
    setLoading(true);
    setMessage(null);

    try {
      const res = await fetch("/api/cli-tools/antigravity-mitm/alias", {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ tool: "antigravity", mappings: modelMappings }),
      });

      if (!res.ok) {
        const data = await res.json();
        throw new Error(data.error || "Failed to save mappings");
      }

      setMessage({ type: "success", text: "Mappings saved!" });
    } catch (error) {
      setMessage({ type: "error", text: error.message });
    } finally {
      setLoading(false);
    }
  };

  const isRunning = status?.running;

  return (
    <Card padding="xs" className="overflow-hidden">
      <div className="flex items-start justify-between gap-3 hover:cursor-pointer sm:items-center" onClick={onToggle}>
        <div className="flex min-w-0 items-center gap-3">
          <div className="size-8 flex items-center justify-center shrink-0">
            <Image

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Check the server response/network tab for the actual status code and error body from the mappings endpoint
  2. Re-authenticate (log back into the dashboard) and retry the save
  3. Validate that every mapping's model id still exists in the provider's model list before saving
  4. Verify the DB is writable (check ~/.9router permissions / disk space) and the server log for the underlying write error

Example fix

// before
if (!res.ok) {
  const data = await res.json();
  throw new Error(data.error || "Failed to save mappings");
}
// after
if (!res.ok) {
  const data = await res.json().catch(() => ({}));
  if (res.status === 401) throw new Error("Session expired — please log in again");
  throw new Error(data.error || `Failed to save mappings (HTTP ${res.status})`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before saving
const invalid = Object.entries(modelMappings).filter(([k, v]) => !k || !v);
if (invalid.length) throw new Error("All mappings must have non-empty source and target");

Try / catch

try {
  const res = await fetch("/api/cli-tools/...", { method: "POST", body: JSON.stringify({ tool: "antigravity", mappings: modelMappings }) });
  const data = res.ok ? await res.json() : await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(data.error || `Failed to save mappings (HTTP ${res.status})`);
} catch (e) {
  setMessage({ type: "error", text: e.message });
}

Prevention

When it happens

Trigger: POST /api/cli-tools/... with {tool:'antigravity', mappings} fails: session expired (401), a mapping references a model the backend cannot resolve (400), or the persistence layer errors while writing mappings (500); also thrown verbatim when res.ok is false and data.error is empty.

Common situations: Dashboard session cookie expired mid-edit; pasted a mapping whose target model id was renamed or removed; SQLite DB locked or read-only; server restarted between opening the card and clicking save.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/beddb0ef304a313a. Report an issue: GitHub.