badges/shields · error · NotFound

no packages found

Error message

no packages found

What it means

The F-Droid service fetches package metadata and filters json.packages down to entries whose versionCode is at or below the suggestedVersionCode (when one is present). If no packages remain after filtering, it throws NotFound with prettyMessage 'no packages found', meaning F-Droid reports no usable package builds for this app.

Source

Thrown at services/f-droid/f-droid.service.js:78

    baseUrl = baseUrl.replace(/\/$/, '')
    const url = `${baseUrl}/api/v1/packages/${appId}`
    return this._requestJson({
      schema,
      url,
      httpErrors: {
        403: 'app not found',
        404: 'app not found',
      },
    })
  }

  transform({ json, suggested }) {
    const svc = suggested && json.suggestedVersionCode
    const packages = (json.packages || []).filter(
      ({ versionCode }) => !svc || versionCode <= svc,
    )
    if (packages.length === 0) {
      throw new NotFound({ prettyMessage: 'no packages found' })
    }
    const version = packages.reduce((a, b) =>
      a.versionCode > b.versionCode ? a : b,
    ).versionName
    return { version }
  }

  async handle(
    { appId },
    { baseUrl = 'https://f-droid.org', include_prereleases: includePre },
  ) {
    const json = await this.fetch({ baseUrl, appId })
    const suggested = includePre === undefined
    const { version } = this.transform({ json, suggested })
    return renderVersionBadge({ version })
  }
}

View on GitHub (pinned to 766fd8bc89)

Solutions

  1. Verify the app id in the F-Droid index and confirm it has published packages
  2. Check the F-Droid index JSON for the app to see whether packages is empty or filtered out by suggestedVersionCode
  3. Pin/choose a different F-Droid mirror or index that includes the builds
  4. Wait for F-Droid to publish a build within the suggested version range

Example fix

// before
/badge/f-droid/v/org.fdroid.wrongid
// after
/badge/f-droid/v/org.fdroid.fdroid
Defensive patterns

Strategy: validation

Validate before calling

async function fdroidHasPackages(appId) {
  const res = await fetch(`https://f-droid.org/api/v1/packages/${appId}`)
  if (!res.ok) return false
  const json = await res.json()
  return Array.isArray(json.packages) && json.packages.length > 0
}
// verify before rendering the badge

Type guard

function hasPackages(json) {
  return Array.isArray(json.packages) && json.packages.length > 0
}

Try / catch

try {
  const badge = await getFDroidVersionBadge(appId)
} catch (e) {
  if (e.prettyMessage === 'no packages found') {
    renderPlaceholderBadge('not published')
  } else throw e
}

Prevention

When it happens

Trigger: Requesting an F-Droid version badge for an app whose packages array is empty or whose packages all have versionCodes above suggestedVersionCode (e.g. all builds marked unstable/newer than suggested).

Common situations: Newly published apps with no package builds yet; apps where every package was archived or is a pre-release above the suggested version; typos in the app id returning a metadata stub with no packages.

Related errors


AI-assisted analysis of badges/shields@766fd8bc89 (2026-08-30). Data as JSON: /api/errors/bffe7dbe7d8a0a8d. Report an issue: GitHub.