jackwener/OpenCLI · error · CommandExecutionError

Manus credits returned a malformed API payload

Error message

Manus credits returned a malformed API payload

What it means

The manus credits command calls user.v1.UserService/GetAvailableCredits and throws this CommandExecutionError when the response object contains none of the expected credit fields (totalCredits, freeCredits, periodicCredits, refreshCredits). It means the API responded but with a payload the command cannot interpret as credits data.

Source

Thrown at clis/manus/credits.js:26

    access: 'read',
    description: 'Show Manus credit balance and refresh details.',
    domain: MANUS_DOMAIN,
    strategy: Strategy.COOKIE,
    browser: true,
    siteSession: 'persistent',
    navigateBefore: true,
    args: [],
    columns: ['Field', 'Value'],
    func: async (page) => {
        await ensureOnManus(page);

        const c = requireObject(await page.evaluate(`(async () => {
            ${MANUS_API_CALL_JS}
            return callManusAPI('user.v1.UserService/GetAvailableCredits', {});
        })()`), 'credits');

        if (!['totalCredits', 'freeCredits', 'periodicCredits', 'refreshCredits'].some((key) => c[key] != null)) {
            throw new CommandExecutionError('Manus credits returned a malformed API payload');
        }
        return [
            { Field: 'Total Credits', Value: c.totalCredits ?? '—' },
            { Field: 'Free Credits', Value: c.freeCredits ?? '—' },
            { Field: 'Periodic Credits', Value: c.periodicCredits ?? '—' },
            { Field: 'Pro Monthly Credits', Value: c.proMonthlyCredits ?? '—' },
            { Field: 'Refresh Credits', Value: c.refreshCredits ?? '—' },
            { Field: 'Max Refresh Credits', Value: c.maxRefreshCredits ?? '—' },
            { Field: 'Next Refresh', Value: c.nextRefreshTime || '—' },
            { Field: 'Refresh Interval', Value: c.refreshInterval || '—' },
        ];
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Refresh the session by re-running the manus auth/login flow, then retry the credits command
  2. Log the raw `c` object from the evaluate result to see what GetAvailableCredits actually returned
  3. Check whether Manus changed the GetAvailableCredits response schema and update the expected keys in clis/manus/credits.js
  4. Retry later — transient gateway/bot-challenge responses can masquerade as malformed payloads

Example fix

// before
if (!['totalCredits', 'freeCredits', 'periodicCredits', 'refreshCredits'].some((key) => c[key] != null)) {
    throw new CommandExecutionError('Manus credits returned a malformed API payload');
}
// after (include raw payload for diagnosability)
if (!['totalCredits', 'freeCredits', 'periodicCredits', 'refreshCredits'].some((key) => c[key] != null)) {
    throw new CommandExecutionError(`Manus credits returned a malformed API payload: ${JSON.stringify(c).slice(0, 500)}`);
}
Defensive patterns

Strategy: validation

Validate before calling

const credits = await page.evaluate(`(async () => {
  ${MANUS_API_CALL_JS}
  return callManusAPI('user.v1.UserService/GetAvailableCredits', {});
})()`);
const keys = ['totalCredits','freeCredits','periodicCredits','refreshCredits'];
if (!credits || !keys.some(k => credits[k] != null)) {
  throw new Error('GetAvailableCredits payload lacks credit fields: ' + JSON.stringify(credits));
}

Type guard

function hasCreditFields(c) {
  return c != null && typeof c === 'object' &&
    ['totalCredits','freeCredits','periodicCredits','refreshCredits'].some(k => c[k] != null);
}

Try / catch

try {
  const rows = await manusCredits();
} catch (e) {
  if (e instanceof CommandExecutionError && /malformed API payload/.test(e.message)) {
    await refreshManusSession();
    return manusCredits(); // one retry after re-auth
  }
  throw e;
}

Prevention

When it happens

Trigger: GetAvailableCredits returns 200/OK with a body lacking all four credit keys — e.g. an empty object, an error envelope, or a response whose field names changed after a Manus API update.

Common situations: Manus renamed or restructured credit fields in a newer API version; the session is valid but the account tier doesn't expose credit fields; a gateway/anti-bot layer returned a 200 HTML or challenge payload instead of the RPC result; RPC responded with an error status the wrapper still surfaced as an object.

Understand the failure class

Related errors


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