jackwener/OpenCLI · error · CommandExecutionError

packagist package returned no "package" object for ${full}.

Error message

packagist package returned no "package" object for ${full}.

What it means

Packagist's /packages/<vendor>/<name>.json endpoint responded, but the JSON body had no usable `package` object (missing, null, or not an object). Thrown as a CommandExecutionError because it indicates the response shape differs from what the CLI expects.

Source

Thrown at clis/packagist/package.js:28

cli({
    site: 'packagist',
    name: 'package',
    access: 'read',
    description: 'Fetch a Packagist package\'s metadata (version, downloads, license, repo, GitHub stars)',
    domain: 'packagist.org',
    strategy: Strategy.PUBLIC,
    browser: false,
    args: [
        { name: 'name', positional: true, required: true, help: 'Composer package "<vendor>/<package>" (e.g. "symfony/console", "monolog/monolog")' },
    ],
    columns: ['package', 'version', 'releasedAt', 'license', 'description', 'repository', 'githubStars', 'favers', 'downloads', 'monthlyDownloads', 'dailyDownloads', 'url'],
    func: async (args) => {
        const { full } = requirePackageName(args.name);
        const url = `${PACKAGIST_BASE}/packages/${full}.json`;
        const body = await packagistFetch(url, 'packagist package');
        const pkg = body?.package;
        if (!pkg || typeof pkg !== 'object') {
            throw new CommandExecutionError(`packagist package returned no "package" object for ${full}.`);
        }
        const versionKey = pickStableVersion(pkg.versions);
        const versionEntry = versionKey ? pkg.versions?.[versionKey] : null;
        const license = Array.isArray(versionEntry?.license) ? versionEntry.license.filter(Boolean).join(', ') : '';
        const downloads = pkg.downloads ?? {};
        return [{
            package: String(pkg.name ?? full).trim(),
            version: versionKey ? String(versionKey) : '',
            releasedAt: trimDate(versionEntry?.time),
            license,
            description: String(pkg.description ?? '').trim(),
            repository: String(pkg.repository ?? '').trim(),
            githubStars: pkg.github_stars != null ? Number(pkg.github_stars) : null,
            favers: pkg.favers != null ? Number(pkg.favers) : null,
            downloads: downloads.total != null ? Number(downloads.total) : null,
            monthlyDownloads: downloads.monthly != null ? Number(downloads.monthly) : null,
            dailyDownloads: downloads.daily != null ? Number(downloads.daily) : null,
            url: `https://packagist.org/packages/${full}`,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the raw response body from `${PACKAGIST_BASE}/packages/${full}.json` to see what was actually returned
  2. Verify the package exists: open the same URL or https://packagist.org/packages/<vendor>/<name> in a browser
  3. Update the CLI — Packagist occasionally adjusts its JSON schema
  4. Confirm packagistFetch isn't swallowing error statuses and returning a non-package body

Example fix

// before
const pkg = body?.package;
if (!pkg) throw new Error('no package');
// after
const pkg = body?.package ?? body?.['package'] ?? null;
if (!pkg || typeof pkg !== 'object') {
  console.error('Unexpected Packagist payload:', JSON.stringify(body).slice(0, 300));
  throw new Error('no package object');
}
Defensive patterns

Strategy: validation

Validate before calling

const url = `https://repo.packagist.org/p2/${vendor}/${name}.json`;
const ok = await fetch(url).then(r => r.ok).catch(() => false);
if (!ok) throw new Error(`Package ${vendor}/${name} not found on Packagist`);

Type guard

function isPackagistPackageBody(b) { return b != null && typeof b === 'object' && b.package != null && typeof b.package === 'object'; }

Try / catch

try {
  const info = await packagistPackage('vendor/name');
  return info;
} catch (e) {
  if (/no "package" object/.test(e.message)) {
    console.error('Unexpected Packagist payload — check schema or package existence');
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: `packagist package` fetched `${PACKAGIST_BASE}/packages/${full}.json` after requirePackageName parsed the name; the response JSON parsed but `body.package` was absent or not an object — e.g. Packagist changed its schema or served an error page as JSON.

Common situations: Packagist API schema change; the fetch layer returning an error envelope (e.g. {status:'error'}) instead of package data; a cached/proxied response missing the package key; querying a package that exists in search but whose detail endpoint returns an empty document.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/e82831a0482e5e10. Report an issue: GitHub.