jackwener/OpenCLI · error · CommandExecutionError

Flomo API returned HTTP ${resp.status}

Error message

Flomo API returned HTTP ${resp.status}

What it means

fetchFlomoJson throws this CommandExecutionError when the Flomo API responds with any non-OK HTTP status other than 401/403 (e.g. 404, 429, 500, 502, 503). The CLI surfaces the bare status code so callers know the request reached the server but was rejected or failed server-side. 401/403 are deliberately excluded and raised as AuthRequiredError instead.

Source

Thrown at clis/flomo/memos.js:162

async function fetchFlomoJson(url, token) {
  let resp;
  try {
    resp = await fetch(url, {
      headers: {
        Authorization: 'Bearer ' + token,
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        Accept: 'application/json',
      },
    });
  } catch (err) {
    throw new CommandExecutionError(`Failed to fetch Flomo memos: ${err instanceof Error ? err.message : String(err)}`);
  }
  if (resp.status === 401 || resp.status === 403) {
    throw new AuthRequiredError(FLOMO_API_DOMAIN, `Flomo API returned HTTP ${resp.status}; please refresh your Flomo login session`);
  }
  if (!resp.ok) {
    throw new CommandExecutionError(`Flomo API returned HTTP ${resp.status}`);
  }
  try {
    return await resp.json();
  } catch (err) {
    throw new CommandExecutionError(`Flomo API returned malformed JSON: ${err instanceof Error ? err.message : String(err)}`);
  }
}

async function readAccessToken(page) {
  const token = unwrapBrowserResult(await page.evaluate(buildGetTokenJs()));
  if (typeof token !== 'string' || !token.trim()) {
    throw new AuthRequiredError(FLOMO_API_DOMAIN, 'Flomo memos requires an active signed-in Flomo browser session');
  }
  return token.trim();
}

const command = cli({
  site: 'flomo',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. If status is 429, wait and back off before retrying — reduce call frequency.
  2. For 5xx, check Flomo's service status and retry later; it is a server-side issue.
  3. Ensure the CLI/opencli package is up to date in case the signed endpoint or parameters changed.
  4. Verify your system clock is accurate, since the request signature includes the current timestamp.
  5. For persistent non-transient statuses (e.g. 404), add retry-with-backoff only around 429/5xx and surface others directly.

Example fix

// before: no distinction between retryable and fatal statuses
await fetchFlomoJson(url, token);
// after: caller retries only transient statuses
const retry = [429, 500, 502, 503, 504];
for (let i = 0; ; i++) {
  try { return await fetchFlomoJson(url, token); }
  catch (e) {
    const m = /HTTP (\d+)/.exec(e.message);
    if (!m || !retry.includes(Number(m[1])) || i >= 3) throw e;
    await new Promise((r) => setTimeout(r, 2 ** i * 1000));
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// no caller-side check can prevent server-side statuses; optionally pre-check service health
const health = await fetch('https://flomoapp.com', { method: 'HEAD' }).then((r) => r.status).catch(() => 0);
if (health >= 500) console.warn('Flomo appears to be having server issues; expect HTTP 5xx');

Type guard

null

Try / catch

const RETRYABLE = new Set([429, 500, 502, 503, 504]);
try {
  body = await fetchFlomoJson(url, token);
} catch (err) {
  const m = /HTTP (\d+)/.exec(err.message || '');
  if (m && RETRYABLE.has(Number(m[1]))) {
    for (let i = 1; i <= 3; i++) {
      await new Promise((r) => setTimeout(r, 2 ** i * 1000));
      try { body = await fetchFlomoJson(url, token); break; } catch {}
    }
  }
  if (!body) throw err;
}

Prevention

When it happens

Trigger: Calling `flomo memos` during Flomo server incidents (5xx); rate limiting (429) from too-frequent calls; 404 if the /api/v1/memo/updated/ endpoint path or the pinned app_version 4.0 sign parameters become invalid; 400 from an invalid signature/timestamp combination.

Common situations: Hammering the CLI in a loop and hitting Flomo rate limits; Flomo outage or maintenance window; API version drift breaking the MD5-signed request parameters; misconfigured system clock producing bad `timestamp`/`sign` values.

Related errors


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