jackwener/OpenCLI · error · CommandExecutionError

nuget package registration page ${pageIndex + 1} is missing

Error message

nuget package registration page ${pageIndex + 1} is missing @id for package "${id}"

What it means

When building nuget package registration metadata, the code paginates through the NuGet registration API. Each page should carry an '@id' string URL pointing to the leaf page containing its items. If a page object has no items array and also lacks a usable '@id', the adapter cannot resolve that page, so it throws CommandExecutionError. This guards against malformed or unexpected registration payloads from the NuGet service.

Source

Thrown at clis/nuget/package.js:49

        'listed',
        'url',
    ],
    func: async (args) => {
        const id = requirePackageId(args.id);
        const url = `${NUGET_REGISTRATION_BASE}/${encodeURIComponent(id.toLowerCase())}/index.json`;
        const body = await nugetFetch(url, 'nuget package');
        const pages = Array.isArray(body?.items) ? body.items : [];
        // Each page can be inline (with `items`) or a stub that needs another fetch
        // for older packages. Inline is the common case for everything published in
        // the last few years. We follow stub pages once each — at most ~5 round-trips.
        const allEntries = [];
        for (const [pageIndex, page] of pages.entries()) {
            let pageItems = Array.isArray(page?.items) ? page.items : null;
            if (!pageItems) {
                // Stub page → fetch the leaf.
                const pageUrl = typeof page?.['@id'] === 'string' ? page['@id'] : null;
                if (!pageUrl) {
                    throw new CommandExecutionError(
                        `nuget package registration page ${pageIndex + 1} is missing @id for package "${id}"`,
                    );
                }
                const leaf = await nugetFetch(pageUrl, 'nuget package page');
                if (!Array.isArray(leaf?.items)) {
                    throw new CommandExecutionError(
                        `nuget package registration leaf ${pageUrl} did not include an items array`,
                    );
                }
                pageItems = leaf.items;
            }
            for (const it of pageItems) {
                if (!it || typeof it !== 'object' || !it.catalogEntry || typeof it.catalogEntry !== 'object') {
                    throw new CommandExecutionError(
                        `nuget package registration page ${pageIndex + 1} contains a malformed version entry`,
                    );
                }
                allEntries.push(it);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the request — incomplete registration payloads from a partial NuGet response often resolve on retry
  2. Verify the package's registration index directly: GET https://api.nuget.org/v3/registration5-gz-semver2/<id>/index.json (with appropriate content encoding) and inspect page '@id' values
  3. Check https://status.nuget.org for a NuGet service incident if the payload looks systematically malformed
  4. If it persists for a specific package, the index may be corrupt on the service side — report it to NuGet or fall back to the flat container API for version listing

Example fix

// before
const index = await nugetFetch(registrationUrl, 'nuget registration');
const versions = collectVersions(index);
// after
const index = await nugetFetch(registrationUrl, 'nuget registration');
const pages = (index?.pages ?? []).filter((p) => Array.isArray(p?.items) || typeof p?.['@id'] === 'string');
if (!pages.length) {
  console.error('NuGet registration index had no resolvable pages; retrying or using flat container API.');
}
const versions = collectVersions({ pages });
Defensive patterns

Strategy: validation

Validate before calling

function hasResolvablePages(index) {
  return Array.isArray(index?.pages) && index.pages.every(
    (p) => Array.isArray(p?.items) || typeof p?.['@id'] === 'string'
  );
}
const index = await nugetFetch(registrationUrl, 'nuget registration');
if (!hasResolvablePages(index)) throw new Error('Registration index has unresolvable pages');

Type guard

function isResolvablePage(page) {
  return page != null &&
    (Array.isArray(page.items) || typeof page['@id'] === 'string');
}

Try / catch

try {
  const data = await collectVersions(id);
  return data;
} catch (err) {
  if (String(err.message).includes('is missing @id')) {
    console.error('NuGet returned an incomplete registration index; retry or use the flat container API.');
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: nugetFetch of a package registration index where an element of pages[] is neither a flat page (missing items array) nor a stub (missing or non-string '@id') — e.g. the NuGet API returns null page entries, an empty object, or '@id' of a type other than string for the package being queried.

Common situations: Packages with very many versions that produce deeply paginated registration indexes where stub pages are expected; NuGet API schema drift or partial outage returning incomplete registration documents; proxies/CDNs truncating the registration JSON so later pages come back as empty objects.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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