jackwener/OpenCLI · error · ArgumentError

Unsupported Nowcoder URL; expected /discuss/<content-id> or

Error message

Unsupported Nowcoder URL; expected /discuss/<content-id> or /feed/main/detail/<moment-uuid>

What it means

parseNowcoderPostTarget accepts a numeric content ID, a moment UUID, or a canonical https://www.nowcoder.com URL. After passing the scheme/host checks, the URL pathname must match either /discuss/<content-id> (positive integer) or /feed/main/detail/<32-hex-char uuid>. Any other well-formed nowcoder.com URL path throws this ArgumentError, because the CLI cannot determine which post detail endpoint to call.

Source

Thrown at clis/nowcoder/posts.js:198

    if (UUID_PATTERN.test(value)) return { post_type: 'moment', value: value.toLowerCase() };

    let url;
    try {
        url = new URL(value);
    }
    catch {
        throw new ArgumentError('nowcoder detail requires a numeric content ID, moment UUID, or canonical Nowcoder URL');
    }
    const host = url.hostname.toLowerCase();
    if (url.protocol !== 'https:' || url.username || url.password || url.port || url.hash
        || (host !== 'nowcoder.com' && host !== 'www.nowcoder.com')) {
        throw new ArgumentError('nowcoder detail only accepts canonical https://www.nowcoder.com post URLs');
    }
    const content = url.pathname.match(/^\/discuss\/([1-9]\d*)\/?$/);
    if (content) return { post_type: 'content', value: content[1] };
    const moment = url.pathname.match(/^\/feed\/main\/detail\/([0-9a-f]{32})\/?$/i);
    if (moment) return { post_type: 'moment', value: moment[1].toLowerCase() };
    throw new ArgumentError('Unsupported Nowcoder URL; expected /discuss/<content-id> or /feed/main/detail/<moment-uuid>');
}

export function projectNowcoderDetail(data, target) {
    if (!isRecord(data) || !isRecord(data.frequencyData)) throw new CommandExecutionError('Nowcoder detail returned malformed post data');
    const isContent = target.post_type === 'content';
    const expectedEntityType = isContent ? CONTENT_ENTITY_TYPE : MOMENT_TYPE;
    if (data.entityType !== expectedEntityType) throw new CommandExecutionError('Nowcoder detail returned a mismatched post entity type');
    const uuid = requiredUuid(data.uuid, `${target.post_type} uuid`);
    const entityId = requiredId(data.entityId, `${target.post_type} entity id`);
    const id = isContent ? requiredId(data.id, 'content id') : uuid;
    if (isContent ? id !== target.value : uuid !== target.value) throw new CommandExecutionError('Nowcoder detail returned a different post identity');
    if (!isContent && entityId !== requiredId(data.id, 'moment id')) throw new CommandExecutionError('Nowcoder detail returned mismatched moment entity ids');
    const expectedAuthorId = isContent ? data.authorId : data.userId;
    const body = cleanBody(isContent ? data.richText : data.content, `${target.post_type} detail body`);
    return {
        post_type: target.post_type,
        id,
        uuid,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use a canonical URL of the form https://www.nowcoder.com/discuss/<numeric-id> or https://www.nowcoder.com/feed/main/detail/<32-hex-uuid>.
  2. Alternatively pass just the numeric content ID or the moment UUID string instead of a URL.
  3. Check the URL for extra path segments, leading zeros, or non-hex characters and correct them.
  4. If the post is not a discuss post or a feed moment, it is not supported — locate the discuss/feed version of the content.

Example fix

// before
nowcoder detail "https://www.nowcoder.com/interview/ai/index"
// after
nowcoder detail "https://www.nowcoder.com/discuss/70123456"
Defensive patterns

Strategy: validation

Validate before calling

function isCanonicalNowcoderUrl(value) {
  if (!/^\d+$/.test(value)) return true; // bare IDs/UUIDs are fine
  try {
    const url = new URL(value);
    const okHost = ['nowcoder.com', 'www.nowcoder.com'].includes(url.hostname.toLowerCase());
    const okPath = /^\/discuss\/[1-9]\d*\/?$/.test(url.pathname)
      || /^\/feed\/main\/detail\/[0-9a-f]{32}\/?$/i.test(url.pathname);
    return url.protocol === 'https:' && okHost && okPath;
  } catch { return true; }
}

Type guard

function isNowcoderDiscussOrFeedUrl(v) {
  return typeof v === 'string' && (/^https:\/\/(www\.)?nowcoder\.com\/discuss\/[1-9]\d*\/?$/.test(v)
    || /^https:\/\/(www\.)?nowcoder\.com\/feed\/main\/detail\/[0-9a-f]{32}\/?$/i.test(v));
}

Try / catch

try {
  await nowcoderDetail(target);
} catch (err) {
  if (err instanceof ArgumentError && /Unsupported Nowcoder URL/.test(err.message)) {
    console.error('Pass /discuss/<id>, /feed/main/detail/<uuid>, or a bare ID/UUID:', err.message);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling nowcoder detail with a nowcoder.com URL whose path is neither /discuss/<numeric-id> nor /feed/main/detail/<32-hex uuid> — e.g. a /interview/main/... link, a /discuss/ path with a non-numeric or zero-padded id (012345), a /feed/main/detail/ uuid that is not exactly 32 hex chars, or a URL with a query string altering the expectation of a trailing path segment.

Common situations: Pasting a Nowcoder link copied from the mobile app or a share dialog that uses a different route format; using a shortened or relative link; passing a URL for another nowcoder product page (jobs, campus, interview questions); typos in the URL; leading zeros or URL-encoded IDs in /discuss/ links.

Related errors


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