Yup—this one’s classic. Your error toast is trying to read .text() on the error object, not on a Response. In a fetch chain, the catch gets an Error, so t.text is not a function pops.

Fix it in two parts:

1) Make a safe apiRequest helper (centralized)
// src/lib/apiRequest.ts
export async function apiRequest<T = unknown>(
  input: RequestInfo | URL,
  init?: RequestInit
): Promise<T> {
  const res = await fetch(input, init);

  const ct = res.headers.get('content-type') || '';
  const body = ct.includes('application/json') ? await res.json() : await res.text();

  if (!res.ok) {
    const message =
      typeof body === 'string'
        ? body
        : body?.message || body?.error || 'Request failed';
    throw new Error(message);
  }

  return body as T;
}

2) Use it in the Domain Search UI
// src/pages/DomainSearch/DomainSearchPage.tsx
import { useState } from "react";
import { apiRequest } from "@/lib/apiRequest";
import { toast } from "@/components/ui/use-toast"; // shadcn style; adjust if needed

type DomainSearchResult = {
  query: string;
  suggestions: Array<{ domain: string; available: boolean; price?: number }>;
};

export default function DomainSearchPage() {
  const [q, setQ] = useState("");
  const [data, setData] = useState<DomainSearchResult | null>(null);
  const [loading, setLoading] = useState(false);

  async function onSearch(e: React.FormEvent) {
    e.preventDefault();
    setLoading(true);
    setData(null);
    try {
      const result = await apiRequest<DomainSearchResult>("/api/domains/search", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ query: q.trim() }),
      });
      setData(result);
    } catch (err: unknown) {
      const message = err instanceof Error ? err.message : "Search failed";
      toast({
        variant: "destructive",
        title: "Search Failed",
        description: message,
      });
    } finally {
      setLoading(false);
    }
  }

  return (
    <form onSubmit={onSearch}>
      {/* your input + button */}
    </form>
  );
}

3) (Optional) Improve your backend error shape

Make sure your /api/domains/search returns JSON errors consistently:

// example Express/Next handler
if (!query) {
  return res.status(400).json({ error: "Missing query" });
}
try {
  // ... call provider
} catch (e) {
  const msg = e instanceof Error ? e.message : "Domain search failed";
  return res.status(502).json({ error: msg });
}

Why this fixes it

We only call .text()/.json() on an actual Response.

On non-OK responses, we throw Error(message), so the UI’s catch receives a normal Error.

The toast then prints err.message (no .text() on an Error = no crash).

If you’d rather not add a helper, at minimum change your current catch(async (t) => { const m = await t.text()… }) to:

} catch (t) {
  const message = t instanceof Error ? t.message : "Search failed";
  toast({ variant: "destructive", title: "Search Failed", description: message });
}