jackwener/OpenCLI · error · ArgumentError

flomo memos --slug must be an opaque memo cursor containing

Error message

flomo memos --slug must be an opaque memo cursor containing only letters, numbers, _ or -

What it means

Thrown by parseSlugArg in clis/flomo/memos.js:57 when the --slug option (an opaque pagination cursor returned by a previous `flomo memos` call) contains characters outside [A-Za-z0-9_-] or exceeds 256 characters. The library validates cursors defensively because they are embedded in signed request URLs; malformed slugs would produce invalid requests.

Source

Thrown at clis/flomo/memos.js:57

  }
  const text = String(value).trim();
  if (!/^\d+$/.test(text)) {
    throw new ArgumentError('flomo memos --since must be a non-negative Unix timestamp in seconds');
  }
  const parsed = Number(text);
  if (!Number.isSafeInteger(parsed)) {
    throw new ArgumentError('flomo memos --since must be a safe integer Unix timestamp in seconds');
  }
  return parsed;
}

function parseSlugArg(value) {
  if (value === undefined || value === null || value === '') {
    return '';
  }
  const slug = String(value).trim();
  if (!/^[A-Za-z0-9_-]{1,256}$/.test(slug)) {
    throw new ArgumentError('flomo memos --slug must be an opaque memo cursor containing only letters, numbers, _ or -');
  }
  return slug;
}

function buildSignedUrl(limit, since, slug) {
  const params = {
    limit: String(limit),
    latest_updated_at: String(since),
    tz: '8:0',
    timestamp: String(Math.floor(Date.now() / 1000)),
    api_key: 'flomo_web',
    app_version: '4.0',
    platform: 'web',
    webp: '1',
  };
  if (slug) params.latest_slug = slug;
  const keys = Object.keys(params).sort();
  const signBase = keys.map((key) => `${key}=${params[key]}`).join('&');

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use the exact `next` / cursor value returned by the previous `flomo memos` invocation, copied whole without wrapping.
  2. If the cursor was URL-encoded (contains %2B, %3D, etc.), decode it once before passing, or re-capture it from raw output.
  3. Store the cursor in a file to avoid shell quoting corruption: `flomo memos --slug "$(cat cursor.txt)"`.
  4. Start a fresh fetch without --slug if the cursor cannot be recovered.

Example fix

// before
flomo memos --slug "eyJwYWdlIjoyfQ==/extra"
// after
flomo memos --slug "eyJwYWdlIjoyfQ"  # exact cursor from previous response
Defensive patterns

Strategy: try-catch

Validate before calling

function isValidSlug(s) { return s === undefined || s === '' || /^[A-Za-z0-9_-]{1,256}$/.test(s); }
if (!isValidSlug(cursor)) throw new Error('cursor corrupted; refetch without --slug');

Type guard

function isOpaqueCursor(v) { return typeof v === 'string' && /^[A-Za-z0-9_-]{1,256}$/.test(v); }

Try / catch

try {
  page = await runMemos({ slug: cursor });
} catch (err) {
  if (err.name === 'ArgumentError' && err.message.includes('--slug')) {
    console.error('Cursor invalid; restarting pagination from the first page.');
    page = await runMemos({});
  } else { throw err; }
}

Prevention

When it happens

Trigger: `flomo memos --slug "abc/def"`, `--slug "a b"`, `--slug "列表"`, a cursor that was URL-encoded twice (containing %2F), a truncated or hand-edited cursor, or one longer than 256 chars from wrapping/copying errors. Empty or missing slug is fine (returns '').

Common situations: Manually editing or truncating a next-page cursor copied from terminal output with line wrapping, storing the cursor in JSON and losing escaping, or passing a different system's slug/ID that contains dots, slashes, or unicode.

Related errors


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