sickn33/agentic-awesome-skills · error · Error

HTTP ${res.status}

Error message

HTTP ${res.status}

What it means

In the fp-react skill's fetch wrapper, this error is thrown when the HTTP response's `ok` flag is false — any 4xx or 5xx status. The throw happens inside TE.tryCatch's attempt function, so it is automatically captured as the Left of the TaskEither rather than escaping to the caller.

Source

Thrown at skills/fp-react/SKILL.md:254

## 3. Data Fetching with TaskEither

TaskEither = async operation that might fail. Perfect for API calls.

### Basic Fetch Hook

```typescript
import { useState, useEffect } from 'react'
import * as TE from 'fp-ts/TaskEither'
import * as E from 'fp-ts/Either'
import { pipe } from 'fp-ts/function'

// Wrap fetch in TaskEither
const fetchJson = <T>(url: string): TE.TaskEither<Error, T> =>
  TE.tryCatch(
    async () => {
      const res = await fetch(url)
      if (!res.ok) throw new Error(`HTTP ${res.status}`)
      return res.json()
    },
    (err) => err instanceof Error ? err : new Error(String(err))
  )

// Custom hook
function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null)
  const [error, setError] = useState<Error | null>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    setLoading(true)
    setError(null)

    pipe(
      fetchJson<T>(url),
      TE.match(

View on GitHub (pinned to 58d857988f)

Solutions

  1. Inspect res.status (and the response body) before assuming a client bug — the number identifies the class of failure
  2. Ensure auth tokens and correct base URL/headers are attached to fetch
  3. Handle the Left branch of the TaskEither to show user-facing messages per status code

Example fix

// before
const res = await fetch(url)
if (!res.ok) throw new Error(`HTTP ${res.status}`)

// after: enrich the Left with status and body
const fetchJson = <T>(url: string): TE.TaskEither<Error, T> =>
  TE.tryCatch(
    async () => {
      const res = await fetch(url)
      if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`)
      return res.json()
    },
    (err) => err instanceof Error ? err : new Error(String(err))
  )
Defensive patterns

Strategy: try-catch

Type guard

const isOkStatus = (s: number) => s >= 200 && s < 300

Try / catch

// with TaskEither the throw never escapes; handle the Left:
pipe(
  fetchJson<T>(url),
  TE.mapLeft((e) => e.message /* e.g. 'HTTP 401' */)
)

Prevention

When it happens

Trigger: Any fetch(url) returning a non-2xx status: 401 with an expired token, 404 on a mistyped endpoint, 500 from the server, or a 429 rate limit.

Common situations: Missing or expired auth headers in the fetch call; proxy/dev-server rewriting API paths; backend deployed with breaking route changes; CORS preflight failures surfacing as opaque errors.

Related errors


AI-assisted analysis of sickn33/agentic-awesome-skills@58d857988f (2026-08-26). Data as JSON: /api/errors/c490fd511a07c717. Report an issue: GitHub.