fatedier/frp · error · HTTPError

HTTP

Error message

HTTP ${response.status}

What it means

Generic non-2xx failure from the frpc web dashboard's fetch wrapper. Every http.get/post/put/delete call in web/frpc/src/api goes through request(), and any response where response.ok is false throws an HTTPError whose message is just 'HTTP <status>'. The frpc admin API (admin_addr/admin_port) returns 4xx/5xx for bad payloads, unknown resources, or when the admin server is not enabled.

Solutions

  1. Verify frpc is running with webServer (admin) enabled and the dashboard targets that exact host:port
  2. Reproduce the failing call with curl against the admin API to see the raw status code
  3. Inspect err.status in the catch block — the message alone only carries the number
  4. For 401/403 check webServer.user/webServer.password credentials; for 404 check the endpoint path and frpc version

Example fix

// before
const proxies = await http.get('/api/proxy') // throws HTTP 404

// after
try {
  const proxies = await http.get('/api/proxy')
} catch (e) {
  if (e instanceof Error && 'status' in e) {
    console.error('admin API failed with status', (e as any).status)
  }
  throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the frpc admin API is reachable before issuing calls
async function assertAdminApiUp(base: string) {
  const r = await fetch(`${base}/api/status`, { credentials: 'include' })
  if (!r.ok) throw new Error(`frpc admin API not ready: HTTP ${r.status}`)
}

Type guard

function isHTTPError(e: unknown): e is { status: number; statusText: string } & Error {
  return e instanceof Error && typeof (e as any).status === 'number'
}

Try / catch

try {
  const data = await http.get<T>('/api/proxy')
} catch (e) {
  if (isHTTPError(e) && e.status === 404) return null
  if (isHTTPError(e) && e.status === 401) { await relogin(); throw e }
  throw e
}

Prevention

When it happens

Trigger: Calling any frpc admin API endpoint (e.g. /api/proxy, /api/config, /api/status) while frpc's webServer/admin port returns a non-2xx status: 404 for an unknown route on the admin port, 401/403 when authentication is required, 500 when the config manager fails (e.g. invalid config body).

Common situations: Pointing the frpc dashboard at a port that is actually frps (or another service) so every route 404s; frpc started without webServer.serverPort so nothing is listening; an expired admin session; curl-level proxies returning 502 while developing the dashboard.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/f20e1f04a7e114f1. Report an issue: GitHub.

Appendix: source

Thrown at web/frpc/src/api/http.ts:22

  status: number
  statusText: string

  constructor(status: number, statusText: string, message?: string) {
    super(message || statusText)
    this.status = status
    this.statusText = statusText
  }
}

async function request<T>(url: string, options: RequestInit = {}): Promise<T> {
  const defaultOptions: RequestInit = {
    credentials: 'include',
  }

  const response = await fetch(url, { ...defaultOptions, ...options })

  if (!response.ok) {
    throw new HTTPError(
      response.status,
      response.statusText,
      `HTTP ${response.status}`,
    )
  }

  // Handle empty response (e.g. 204 No Content)
  if (response.status === 204) {
    return {} as T
  }

  const contentType = response.headers.get('content-type')
  if (contentType && contentType.includes('application/json')) {
    return response.json()
  }
  return response.text() as unknown as T
}

View on GitHub (pinned to 6c8a8d0a97)