jackwener/OpenCLI · error · CommandExecutionError

Board ${trimmed} returned an unusable url: ${url}

Error message

Board ${trimmed} returned an unusable url: ${url}

What it means

After BoardResource returns a board, resolveBoardTarget splits the board's `url` field into username/slug segments. If the decoded url yields fewer than 2 path segments (e.g. empty, '/' or a malformed value), it throws this CommandExecutionError because the code cannot derive a `<username>/<slug>` path from it.

Source

Thrown at clis/pinterest/utils.js:307

      `Not a board reference: "${trimmed}"`,
      'Expected <username>/<slug>, a board URL, or a numeric board id (from `board-pins`/`user-boards`)',
    );
  }

  await page.goto(`${PINTEREST_BASE}/`);
  const { data: board } = await pinterestResourceFetch(
    page,
    'BoardResource',
    { board_id: trimmed, field_set_key: 'detailed' },
    '/',
  );
  const url = board && board.url;
  if (!url) {
    throw new ArgumentError(`No board with id "${trimmed}"`, 'Check the id with `opencli pinterest user-boards <username>`');
  }
  const parts = decodeSegment(url).split('/').filter(Boolean);
  if (parts.length < 2) {
    throw new CommandExecutionError(`Board ${trimmed} returned an unusable url: ${url}`);
  }
  // Hand the fetched board back so callers do not re-request what we already have.
  return { username: parts[0], slug: parts[1], path: `/${parts[0]}/${parts[1]}/`, board };
}

/**
 * Resolve a --section value against the board's real sections, accepting an id or a slug.
 * Pinterest ignores an unknown section silently, so an unmatched value must fail here.
 * Returns { sectionId, title, slug }.
 */
export async function resolveSection(page, boardId, sectionValue, sourceUrl) {
  const wanted = String(sectionValue ?? '').trim();
  const { results } = await pinterestResourceFetch(page, 'BoardSectionsResource', { board_id: String(boardId) }, sourceUrl);
  const sections = results.filter((section) => section && section.id);
  if (sections.length === 0) {
    throw new ArgumentError(`Board has no sections, so --section "${wanted}" cannot be used`, 'Create one first with `opencli pinterest board-section-create`');
  }
  const folded = normalizeForMatch(wanted);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the command — a transient/partial API response may resolve correctly next time.
  2. Pass the board as `<username>/<slug>` or a full board URL so no BoardResource url-parsing is needed.
  3. Print the raw board payload (verbose/debug mode) and inspect the `url` field to confirm the schema.
  4. Update the CLI if Pinterest changed the BoardResource response shape.

Example fix

// before
--board 5123456789012345   # BoardResource returned url: '/'
// after
--board someuser/recipe-ideas
Defensive patterns

Strategy: fallback

Type guard

function hasUsableBoardUrl(board) {
  return !!board && typeof board.url === 'string'
    && board.url.split('/').filter(Boolean).length >= 2;
}

Try / catch

try {
  await runCmd(['--board', numericId]);
} catch (err) {
  if (String(err.message).includes('returned an unusable url')) {
    // fall back to explicit username/slug reference
    await runCmd(['--board', `${username}/${slug}`]);
  } else throw err;
}

Prevention

When it happens

Trigger: BoardResource returns a board object whose `url` field is missing segments, empty, or in an unexpected format — e.g. truncated API response, Pinterest schema change, or a server-side stub/placeholder board object.

Common situations: Pinterest API schema drift (url field renamed or shaped differently); rate-limited/partial responses returning a minimal board object; a proxy or test fixture returning a fake board payload with url:'/'.

Related errors


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