jackwener/OpenCLI · error · CliError

NOT_FOUND

NOT_FOUND

Error message

Episode not found

What it means

Thrown by the Xiaoyuzhou episode info command (clis/xiaoyuzhou/episode.js:23) as a CliError with code NOT_FOUND when /v1/episode/get returns successfully but response.data is falsy. Same root cause as error 4902 but in the metadata/info code path: the library cannot display details for an episode the API does not return.

Source

Thrown at clis/xiaoyuzhou/episode.js:23

cli({
    site: 'xiaoyuzhou',
    name: 'episode',
    access: 'read',
    description: 'View details of a Xiaoyuzhou podcast episode',
    domain: 'www.xiaoyuzhoufm.com',
    strategy: Strategy.LOCAL,
    browser: false,
    args: [{ name: 'id', positional: true, required: true, help: 'Episode ID (eid from podcast-episodes output)' }],
    columns: ['title', 'podcast', 'duration', 'plays', 'comments', 'likes', 'date'],
    func: async (args) => {
        const credentials = loadXiaoyuzhouCredentials();
        const response = await requestXiaoyuzhouJson('/v1/episode/get', {
            query: { eid: args.id },
            credentials,
        });
        const ep = response.data;
        if (!ep)
            throw new CliError('NOT_FOUND', 'Episode not found', 'Please check the ID');
        return [{
                title: ep.title,
                podcast: ep.podcast?.title,
                duration: formatDuration(ep.duration),
                plays: ep.playCount,
                comments: ep.commentCount,
                likes: ep.clapCount,
                date: formatDate(ep.pubDate),
            }];
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the episode ID against the episode's share URL (segment after /episode/)
  2. Ensure you are passing an episode ID, not a podcast (pid) or user ID
  3. Refresh credentials and retry in case an expired token is causing empty data
  4. If the episode was deleted or is access-restricted, it cannot be fetched — choose another episode

Example fix

// before
await cli.episode({ id: '62d0f3ea' }); // truncated
// after
await cli.episode({ id: '62d0f3ea9a1f2b1a3c4d5e6f' }); // full ID from episode URL
Defensive patterns

Strategy: validation

Validate before calling

function isValidEpisodeId(id) {
  return typeof id === 'string' && /^[0-9a-f]{24}$/.test(id);
}
if (!isValidEpisodeId(args.id)) throw new Error('Provide the full 24-char episode ID from the episode share URL');

Type guard

function hasEpisodeData(res) {
  return res != null && typeof res === 'object' && res.data != null && typeof res.data === 'object';
}

Try / catch

try {
  const info = await cli.episode({ id });
} catch (error) {
  if (error.code === 'NOT_FOUND') {
    console.error(`No episode found for ${id} — check the ID (eid, not pid) and that the episode still exists`);
  } else throw error;
}

Prevention

When it happens

Trigger: Running the xiaoyuzhou episode command with an --id the API cannot resolve: nonexistent, deleted, private, or mistyped episode ID, or credentials whose token scope excludes the episode so data comes back empty.

Common situations: Typos when hand-typing the 24-char episode ID; referencing an episode from a podcast that removed it; expired auth token silently yielding empty data instead of an auth error; passing a podcast ID where an episode ID is expected.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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