stablyai/orca · error · Error

GitHub releases response page ${page} for ${repo} was not an

Error message

GitHub releases response page ${page} for ${repo} was not an array

What it means

fetchReleases paginates /releases with per_page=100 and expects each page to be a JSON array. It throws when a page response is not an array, surfacing the page number and repo. A non-array page indicates the API returned an error object, a rate-limit document, or an unexpected shape rather than the release list, so continuing to paginate would be wrong.

Source

Thrown at config/scripts/latest-stable-release.mjs:63

}

export async function fetchReleases(repo, token, fetchImpl = fetch) {
  if (!repo) {
    throw new Error('repo is required')
  }
  if (!token) {
    throw new Error('token is required')
  }

  const releases = []
  for (let page = 1; ; page += 1) {
    const pageReleases = await githubJson(
      fetchImpl,
      `https://api.github.com/repos/${repo}/releases?per_page=100&page=${page}`,
      token
    )
    if (!Array.isArray(pageReleases)) {
      throw new Error(`GitHub releases response page ${page} for ${repo} was not an array`)
    }

    releases.push(...pageReleases)
    if (pageReleases.length < 100) {
      break
    }
  }

  return releases
}

async function main() {
  const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN
  const repo = process.env.GITHUB_REPOSITORY || 'stablyai/orca'
  const releases = await fetchReleases(repo, token)
  process.stdout.write(latestStableDesktopReleaseTag(releases))
}

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Inspect the response body that preceded the throw (the message includes page and repo; capture the body separately to diagnose).
  2. Verify the token and rate-limit status, since some non-array 200s are rate-limit related.
  3. Confirm X-GitHub-Api-Version still matches the supported API version.
  4. Handle the non-array page in the caller instead of treating it as a hard failure.

Example fix

// before
if (!Array.isArray(pageReleases)) {
  throw new Error(`GitHub releases response page ${page} for ${repo} was not an array`)
}

// after — capture the body for diagnosis before failing
if (!Array.isArray(pageReleases)) {
  throw new Error(`GitHub releases response page ${page} for ${repo} was not an array; body=${JSON.stringify(pageReleases).slice(0, 300)}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

const sample = await githubJson(fetchImpl, urlPage1, token)
if (!Array.isArray(sample)) {
  throw new Error(`Unexpected releases shape for ${repo}: ${JSON.stringify(sample).slice(0,300)}`)
}

Type guard

function isReleaseArray(value: unknown): value is unknown[] {
  return Array.isArray(value)
}

Try / catch

try {
  releases = await fetchReleases(repo, token)
} catch (err) {
  if (/was not an array/.test(err.message)) {
    log.warn(`GitHub returned a non-array releases page for ${repo}; possible rate limit or proxy`)
  }
  throw err
}

Prevention

When it happens

Trigger: GitHub returns a 200 with a non-array body (rare, e.g. an API gateway error document or an abuse-rate-limit object); a proxy/interceptor rewrites the response; the endpoint contract changes.

Common situations: An enterprise/proxy returning an HTML or object error body with status 200; an API change after a GitHub API version bump; a rate-limit response that still carries 200.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/46ed7f27806fab80. Report an issue: GitHub.