jackwener/OpenCLI · error · Error

relay_unavailable

relay_unavailable

Error message

[taxonomy=relay_unavailable] site=${site} command=detail missing required detail url

What it means

runProcurementDetail requires a target URL to open a detail page. If the url argument is empty or whitespace-only after cleanText, it throws a taxonomy error with code 'relay_unavailable' and detail 'missing required detail url' — the relay/data source gave nothing to fetch.

Source

Thrown at clis/jianyu/shared/procurement-detail.js:50

      const bodyText = clean(document.body ? document.body.innerText : '');
      const maxLength = 12000;
      const limitedText = bodyText.length > maxLength ? bodyText.slice(0, maxLength) : bodyText;
      const dateMatch = limitedText.match(/(20\\d{2})[.\\-/年](\\d{1,2})[.\\-/月](\\d{1,2})/);
      const publishTime = dateMatch
        ? dateMatch[1] + '-' + String(dateMatch[2]).padStart(2, '0') + '-' + String(dateMatch[3]).padStart(2, '0')
        : '';
      return {
        title,
        detailText: limitedText,
        publishTime,
      };
    })()
  `);
}
export async function runProcurementDetail(page, { url, site, query = '', }) {
    const targetUrl = cleanText(url);
    if (!targetUrl) {
        throw taxonomyError('relay_unavailable', {
            site,
            command: 'detail',
            detail: 'missing required detail url',
        });
    }
    let lastError = null;
    for (let attempt = 1; attempt <= DETAIL_MAX_ATTEMPTS; attempt += 1) {
        try {
            const payload = await extractDetailPayload(page, targetUrl);
            if (!payload || typeof payload !== 'object') {
                throw taxonomyError('extraction_drift', {
                    site,
                    command: 'detail',
                    detail: `detail extraction returned invalid payload: ${targetUrl}`,
                });
            }
            const row = payload;
            const title = cleanText(row.title);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a non-empty url to the detail command
  2. Check the upstream search row actually contains a detail link before calling detail
  3. Fix the list-page parser if the URL field is being dropped
  4. Add a pre-call check that skips/flags rows without URLs

Example fix

// before
await runProcurementDetail(page, { site: 'jianyu', url: row.link });
// after
if (row.link && row.link.trim()) {
  await runProcurementDetail(page, { site: 'jianyu', url: row.link });
} else {
  console.warn('skip row without detail url', row.id);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!url || !String(url).trim()) {
  throw new Error('refusing to call detail without a url');
}

Type guard

function hasDetailUrl(row) {
  return typeof row?.link === 'string' && row.link.trim().length > 0;
}

Try / catch

try {
  await runProcurementDetail(page, { site, url });
} catch (e) {
  if (/\[taxonomy=relay_unavailable\]/.test(e.message)) {
    console.warn('skipping row: no detail url');
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the procurement 'detail' command with url undefined, empty string, or a value that normalizes to empty (e.g. an upstream search row missing its link field).

Common situations: Downstream code passing a row whose URL field was not extracted (parsing drift), shell/CLI invocations omitting the --url argument, upstream list API returning items without detail links.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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