QuantumNous/new-api · info · Error

Unexpected release payload

Error message

Unexpected release payload

What it means

Thrown when the GitHub releases response is HTTP 200 but the JSON lacks tag_name. The dashboard casts the parsed body to ReleaseInfo without runtime validation, so a proxy interstitial, captive portal HTML page parsed as JSON, or API schema change trips this guard.

Source

Thrown at web/src/features/system-settings/maintenance/update-checker-section.tsx:75

    setChecking(true)
    try {
      const response = await fetch(
        'https://api.github.com/repos/Calcium-Ion/new-api/releases/latest',
        {
          headers: {
            Accept: 'application/vnd.github+json',
            'User-Agent': 'new-api-dashboard',
          },
        }
      )

      if (!response.ok) {
        throw new Error(t('Failed to contact GitHub releases API'))
      }

      const data = (await response.json()) as ReleaseInfo
      if (!data?.tag_name) {
        throw new Error(t('Unexpected release payload'))
      }

      if (currentVersion && data.tag_name === currentVersion) {
        toast.success(
          t('You are running the latest version ({{version}}).', {
            version: data.tag_name,
          })
        )
        return
      }

      setRelease(data)
      setDialogOpen(true)
    } catch (error) {
      const message =
        error instanceof Error
          ? error.message
          : t('Failed to check for updates')

View on GitHub (pinned to e2c7aa7b10)

Solutions

  1. Log/inspect the actual parsed body when this fires to see what the endpoint really returned.
  2. If behind an intercepting proxy, fix network egress so the genuine GitHub API responds, or route the check through the backend.
  3. Handle body.html_url, body.name, and published_at with defaults so only tag_name is truly mandatory (already the case).
  4. Verify the repo path (Calcium-Ion/new-api) still exists and the releases API is not returning a 404-shaped 200 from a mirror.
Defensive patterns

Strategy: type-guard

Type guard

interface ReleaseInfo { tag_name: string; name?: string; html_url?: string; published_at?: string }
function isReleaseInfo(data: unknown): data is ReleaseInfo {
  return typeof data === 'object' && data !== null &&
    typeof (data as ReleaseInfo).tag_name === 'string' &&
    (data as ReleaseInfo).tag_name.length > 0
}

Try / catch

const data: unknown = await response.json()
if (!isReleaseInfo(data)) {
  throw new Error(t('Unexpected release payload'))
}

Prevention

When it happens

Trigger: response.json() succeeds but yields an object without tag_name: a transparent proxy returning an HTML/JSON hybrid, GitHub API schema drift, an empty object from a caching layer, or a mirror endpoint with a different response shape.

Common situations: Corporate/ISP captive portals intercepting api.github.com; CDN cache serving a truncated body; future GitHub API changes renaming tag_name; custom build environments pointing at a GitHub Enterprise endpoint with a different payload.

Related errors


AI-assisted analysis of QuantumNous/new-api@e2c7aa7b10 (2026-08-15). Data as JSON: /api/errors/653703a81961a6aa. Report an issue: GitHub.