MiniMax-AI/skills · error · Error

HTTP ${r.status}

Error message

HTTP ${r.status}

What it means

`if (!r.ok) throw new Error(`HTTP ${r.status}`)` inside the React Native `api.get` fetch wrapper. The Fetch API only rejects on network failures; HTTP error statuses (4xx/5xx) resolve as a normal Response with `r.ok === false`. This wrapper converts any non-2xx status into a thrown `Error` so callers' `.then` chains skip on server errors. The message carries the raw status code for diagnosis.

Source

Thrown at skills/react-native-dev/references/engineering.md:204

    users.ts                User-related API calls
    posts.ts                Post-related API calls
  storage/
    secure-store.ts         Wrapper for expo-secure-store
    async-storage.ts        Wrapper for AsyncStorage
  notifications/
    push.ts                 Expo push notification helpers
```

```tsx
// services/api/client.ts
const BASE_URL = process.env.EXPO_PUBLIC_API_URL!;

export const api = {
  get: <T,>(path: string, token?: string) =>
    fetch(`${BASE_URL}${path}`, {
      headers: { Authorization: token ? `Bearer ${token}` : "" },
    }).then(async (r) => {
      if (!r.ok) throw new Error(`HTTP ${r.status}`);
      return r.json() as Promise<T>;
    }),
  // post/put/delete follow same pattern — add method, Content-Type, JSON.stringify(body)
};
```

### Monorepo

```
my-monorepo/
  apps/
    mobile/                 Expo app (all native deps here)
      package.json
      app.json
    web/                    Next.js app
      package.json
  packages/
    ui/                     Shared UI components (no native deps)

View on GitHub (pinned to 60aaae52bb)

Solutions

  1. Read the status code from the message: 401 → refresh/re-login and resend with a valid token; 404 → verify BASE_URL and path; 5xx → retry or check backend health.
  2. Confirm `EXPO_PUBLIC_API_URL` is set in `.env` and rebuild the Expo app (public env vars are inlined at build time, so changes need a rebuild).
  3. Pass the token explicitly: `api.get<T>('/me', userToken)` instead of leaving it undefined on protected routes.
  4. Wrap calls in try/catch and surface a user-facing message; for 401s, redirect to login.

Example fix

// before
const me = await api.get<User>('/me'); // throws 'HTTP 401' if token missing

// after
try {
  const me = await api.get<User>('/me', session?.token);
} catch (e) {
  if (e instanceof Error && e.message === 'HTTP 401') router.replace('/login');
  else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: ensure BASE_URL and token exist before calling.
if (!process.env.EXPO_PUBLIC_API_URL) {
  throw new Error('EXPO_PUBLIC_API_URL is not set');
}
const token = await getToken();
if (!token) { router.replace('/login'); return; }

Type guard

function isHttpError(e: unknown, status?: number): e is Error {
  return e instanceof Error &&
    /^HTTP \d{3}$/.test(e.message) &&
    (status === undefined || e.message === `HTTP ${status}`);
}

Try / catch

try {
  return await api.get<T>(path, token);
} catch (e) {
  if (isHttpError(e, 401)) { await refreshSession(); return api.get<T>(path, token); }
  if (isHttpError(e) && /^HTTP 5\d{2}$/.test(e.message)) throw new RetryableError(e.message);
  throw e;
}

Prevention

When it happens

Trigger: Any request to `${EXPO_PUBLIC_API_URL}${path}` whose response status is not in the 200–299 range: 401 (bad/expired token), 404 (wrong path or BASE_URL), 422/400 (bad payload), 500/502/503 (server/gateway). Also an empty/missing `Authorization` header reaching a protected route.

Common situations: `EXPO_PUBLIC_API_URL` pointing at the wrong host/path, an expired or missing auth token passed as `undefined`, a backend route that changed, CORS preflight rejection surfacing as an opaque error, or a transient 502/503 during deploy.

Related errors


AI-assisted analysis of MiniMax-AI/skills@60aaae52bb (2026-08-13). Data as JSON: /api/errors/2e30213bbe7aa9d0. Report an issue: GitHub.