jackwener/OpenCLI · error · CommandExecutionError

${label} returned an unexpected payload shape; expected an a

Error message

${label} returned an unexpected payload shape; expected an array.

What it means

requirePayloadArray throws this CommandExecutionError when an API response expected to be a JSON array is not an array. It protects row-iterating commands (search results, page lists) from crashing on object/null payloads.

Source

Thrown at clis/_atlassian/shared.js:255

    return s ? `?${s}` : '';
}

export function requireString(value, label) {
    const s = String(value ?? '').trim();
    if (!s) throw new ArgumentError(`${label} is required`);
    return s;
}

export function requirePayloadObject(value, label) {
    if (!value || typeof value !== 'object' || Array.isArray(value)) {
        throw new CommandExecutionError(`${label} returned an unexpected payload shape; expected an object.`);
    }
    return value;
}

export function requirePayloadArray(value, label) {
    if (!Array.isArray(value)) {
        throw new CommandExecutionError(`${label} returned an unexpected payload shape; expected an array.`);
    }
    return value;
}

export function requirePayloadString(value, field, label) {
    if (typeof value !== 'string' && typeof value !== 'number') {
        throw new CommandExecutionError(`${label} did not include a stable ${field}.`);
    }
    const s = String(value).trim();
    if (!s) throw new CommandExecutionError(`${label} did not include a stable ${field}.`);
    return s;
}

export function requireNonEmptyRows(rows, label, hint) {
    if (!rows.length) throw new EmptyResultError(label, hint);
    return rows;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check the deployment mode (cloud vs datacenter) matches your instance — the two return differently shaped list payloads.
  2. Inspect the raw JSON with curl and confirm which field actually holds the array (often .results or .values).
  3. Update the opencli Atlassian adapter if Atlassian changed the response shape.
  4. Ensure the query targets a list endpoint, not a single-resource endpoint.

Example fix

// before (expects bare array but v2 returns envelope)
const rows = requirePayloadArray(body, 'search');
// after
const rows = requirePayloadArray(body.results ?? body, 'search');
Defensive patterns

Strategy: type-guard

Validate before calling

function toRows(body) {
  if (Array.isArray(body)) return body;
  if (isRecord(body) && Array.isArray(body.results)) return body.results;
  if (isRecord(body) && Array.isArray(body.values)) return body.values;
  throw new Error('No array found in response');
}

Type guard

function isNonEmptyArray(v) { return Array.isArray(v); }

Try / catch

try {
  const rows = await listCmd(args);
} catch (e) {
  if (/unexpected payload shape; expected an array/.test(e.message)) {
    console.error('List payload was not an array — inspect raw JSON for the results envelope field.');
  } else throw e;
}

Prevention

When it happens

Trigger: A search/list endpoint returns {results:[...]} while the caller expected a bare array (or vice versa); the endpoint returns an error object; Cloud vs Data Center response envelope mismatch.

Common situations: Version drift between Atlassian Cloud and Data Center list responses; a wrapped response shape after an API upgrade; hitting a search endpoint that returns an object envelope instead of a list.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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