jackwener/OpenCLI · error · CommandExecutionError

Manus skills returned a malformed API payload

Error message

Manus skills returned a malformed API payload

What it means

The `manus skills` command calls `skill.v1.SkillService/ListSkills` and expects the response object to contain at least one of the known skill-list keys: `userAddedSkills`, `systemSkills`, or `skills`. If the payload has none of these keys, the code concludes the API contract changed or the response is not a real skills payload and throws this CommandExecutionError. It is a defensive schema check against Manus API shape drift.

Source

Thrown at clis/manus/skills.js:30

    browser: true,
    siteSession: 'persistent',
    navigateBefore: true,
    args: [],
    columns: ['ID', 'Name', 'Description', 'Source'],
    func: async (page) => {
        await ensureOnManus(page);

        const data = requireObject(await page.evaluate(`(async () => {
            ${MANUS_API_CALL_JS}
            return callManusAPI('skill.v1.SkillService/ListSkills', {});
        })()`), 'skills');

        const rows = [];

        const hasUserSkills = Object.prototype.hasOwnProperty.call(data, 'userAddedSkills');
        const hasSystemSkills = Object.prototype.hasOwnProperty.call(data, 'systemSkills') || Object.prototype.hasOwnProperty.call(data, 'skills');
        if (!hasUserSkills && !hasSystemSkills) {
            throw new CommandExecutionError('Manus skills returned a malformed API payload');
        }

        const userSkills = hasUserSkills ? requireArray(data.userAddedSkills, 'user skills') : [];
        for (const [index, s] of userSkills.entries()) {
            rows.push({
                ID: requireString(s?.id || s?.uid, `user skill ${index + 1}`),
                Name: requireString(s?.name, `user skill ${index + 1}`),
                Description: (s.description || '—').slice(0, 80),
                Source: 'user',
            });
        }

        const systemSkills = Object.prototype.hasOwnProperty.call(data, 'systemSkills')
            ? requireArray(data.systemSkills, 'system skills')
            : (Object.prototype.hasOwnProperty.call(data, 'skills') ? requireArray(data.skills, 'system skills') : []);
        for (const [index, s] of systemSkills.entries()) {
            rows.push({
                ID: requireString(s?.id || s?.uid, `system skill ${index + 1}`),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-login to Manus in the browser profile and retry, to rule out an auth/error response masquerading as a payload.
  2. Update the CLI to the latest version so it matches the current Manus ListSkills response schema.
  3. Inspect the raw response (call ListSkills via devtools on manus.im while logged in) to confirm the field names; report/file an issue if the schema changed.
  4. Wait and retry if Manus is mid-deploy; transient API instability can yield odd payloads.

Example fix

// payload Manus actually returned after a schema change
{"items": [...]}  // no userAddedSkills/systemSkills/skills -> throws

// fix: update the CLI or patch the key check
// before
if (!hasUserSkills && !hasSystemSkills) throw new CommandExecutionError('Manus skills returned a malformed API payload');
// after
const hasItems = Object.prototype.hasOwnProperty.call(data, 'items');
if (!hasUserSkills && !hasSystemSkills && !hasItems) throw new CommandExecutionError('Manus skills returned a malformed API payload');
Defensive patterns

Strategy: try-catch

Type guard

function isSkillsPayload(d) {
  return !!d && typeof d === 'object' &&
    ['userAddedSkills', 'systemSkills', 'skills'].some(k => Object.prototype.hasOwnProperty.call(d, k));
}

Try / catch

try {
  const rows = await run('manus skills');
} catch (e) {
  if (/malformed API payload/.test(e.message)) {
    console.error('Manus API schema may have changed — update the CLI and re-login, then retry.');
  } else throw e;
}

Prevention

When it happens

Trigger: The ListSkills endpoint returns a payload with no `userAddedSkills`/`systemSkills`/`skills` key — e.g. Manus renamed or restructured the response fields, an auth/anti-bot interstitial returned HTML or a different JSON body that still parsed as an object, or the response is an empty object due to a server-side change.

Common situations: Manus shipping a frontend/API update that renames response fields; the CLI's cookie-session page.evaluate getting an unexpected logged-out or error JSON response; regional/API-version differences in the skill service.

Understand the failure class

Related errors


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