jackwener/OpenCLI · error · CommandExecutionError

OpenReview API error for ${label}: ${detail}

Error message

OpenReview API error for ${label}: ${detail}

What it means

openreviewFetch throws CommandExecutionError when the API responds 200 but its JSON envelope carries an application-level error (json.errors array or json.error string). The per-entry messages are stringified and joined into 'detail'. This surfaces OpenReview's own error semantics rather than hiding them as empty data.

Source

Thrown at clis/openreview/utils.js:105

        try { body = (await resp.text()).slice(0, 200); } catch {}
        throw new CommandExecutionError(`OpenReview API HTTP ${resp.status} for ${label}${body ? ` (${body})` : ''}`, 'The OpenReview API may be down or rate-limiting.');
    }
    let json;
    try {
        json = await resp.json();
    }
    catch (e) {
        throw new CommandExecutionError(`Malformed JSON from OpenReview for ${label}: ${e?.message ?? e}`, 'Try again or report this as an OpenReview API bug.');
    }
    const envelopeErrors = Array.isArray(json?.errors) ? json.errors.filter(Boolean) : [];
    const envelopeError = typeof json?.error === 'string' ? json.error.trim() : '';
    if (envelopeErrors.length || envelopeError) {
        const detail = envelopeError || envelopeErrors.map((entry) => {
            if (typeof entry === 'string') return entry;
            if (entry?.message) return String(entry.message);
            return JSON.stringify(entry);
        }).join('; ');
        throw new CommandExecutionError(`OpenReview API error for ${label}: ${detail}`, 'The OpenReview API returned an application-level error.');
    }
    return json;
}

/** Format ms-since-epoch as YYYY-MM-DD; empty string for invalid input. */
export function formatDate(ms) {
    if (typeof ms !== 'number' || !Number.isFinite(ms) || ms <= 0) return '';
    return new Date(ms).toISOString().slice(0, 10);
}

/** Read a v2 content field, which is wrapped as `{ value: ... }`. */
export function readContent(content, key) {
    const v = content?.[key]?.value;
    if (v === undefined || v === null) return undefined;
    return v;
}

/** Build an absolute PDF URL from the `content.pdf` value, which may be a relative `/pdf/<hash>.pdf`. */

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read 'detail' in the message — it states the API's own reason.
  2. Verify the forum/invitation id is current; re-check on openreview.net (venues change year to year).
  3. Ensure you are hitting the correct API version (api2) for 2023+ venues.

Example fix

// before
const json = await openreviewFetch(`/notes?forum=${id}`, label);
// after
try { var json = await openreviewFetch(`/notes?forum=${id}`, label); }
catch (e) { if (/API error/.test(e.message)) { console.error('check the id:', id); } throw e; }
Defensive patterns

Strategy: try-catch

Validate before calling

// verify ids look current before querying
if (!/^[A-Za-z0-9_-]{6,20}$/.test(forumId)) throw new Error('bad forum id');
if (invitationId && !invitationId.includes('/-/')) throw new Error('bad invitation id');

Try / catch

try { const json = await openreviewFetch(path, label); }
catch (e) { if (/OpenReview API error/.test(e.message)) { console.error(e.message, '— verify the id on openreview.net'); process.exit(1); } throw e; }

Prevention

When it happens

Trigger: The OpenReview API returns {error: ...} or {errors: [...]} in the body, e.g. for a malformed invitation id, an unknown forum on certain endpoints, or API-side validation failures.

Common situations: Querying an invitation id that no longer exists (venue renamed, e.g. old year paths); API v1 vs v2 endpoint mismatch for the given id; OpenReview rejecting a query parameter combination.

Related errors


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