DIYgod/RSSHub · error · ConfigNotFoundError

Readwise access token is missing

Error message

Readwise access token is missing

What it means

The Readwise list route needs a personal access token under `config.readwise.accessToken` to authenticate against `readwise.io/api/v3/list/`. If `config.readwise` itself is undefined or its `accessToken` is empty, the handler refuses to run — Readwise returns 401 for any unauthenticated call and there is no public fallback. This is the only entry point for the route.

Source

Thrown at lib/routes/readwise/list.ts:65

\`\`\`
https://rsshub.app/readwise/list/location=new&category=article
\`\`\`

fetches articles in the Inbox.

\`\`\`
https://rsshub.app/readwise/list/category=article&tag=shortlist&tag=AI&tagStrategy=all
\`\`\`

fetches articles tagged both by \`shortlist\` and \`AI\`.`,
};

const TAG_STRATEGY_ALL = 'all'; // Items with tags matching all the given ones can then be returned.
const TAG_STRATEGY_ANY = 'any'; // Items with tags matching any of the given ones can be returned.

async function handler(ctx) {
    if (!config.readwise || !config.readwise.accessToken) {
        throw new ConfigNotFoundError('Readwise access token is missing');
    }

    let apiUrl = 'https://readwise.io/api/v3/list/?';
    let tag, tagStrategy;

    if (ctx.req.param('routeParams')) {
        const urlSearchParams = new URLSearchParams(ctx.req.param('routeParams'));

        const location = urlSearchParams.get('location');
        const category = urlSearchParams.get('category');
        const updatedAfter = urlSearchParams.get('updatedAfter');

        tag = urlSearchParams.get('tag');
        tagStrategy = urlSearchParams.get('tagStrategy') === TAG_STRATEGY_ANY || urlSearchParams.get('tagStrategy') === TAG_STRATEGY_ALL ? urlSearchParams.get('tagStrategy') : TAG_STRATEGY_ANY;

        if (location) {
            apiUrl += `location=${location}&`;
        }

View on GitHub (pinned to bed535e087)

Solutions

  1. Generate a Readwise access token at https://readwise.io/access_token and set `READWISE_ACCESS_TOKEN=<token>` in the RSSHub environment, then restart.
  2. Verify the config block exists; if you load config from a custom file, ensure the `readwise.accessToken` path is populated.
  3. If you do not have an account, the route is simply unavailable — Readwise has no anonymous API.

Example fix

// before
# no readwise config

// after
# .env
READWISE_ACCESS_TOKEN=xxxxxxxxxxxxxxxx
Defensive patterns

Strategy: validation

Validate before calling

if (!config.readwise?.accessToken) {
    return ctx.body('Readwise route requires READWISE_ACCESS_TOKEN.', 503);
}

Type guard

const hasReadwiseToken = (c: typeof config): boolean => Boolean(c.readwise?.accessToken);

Prevention

When it happens

Trigger: A request to /readwise/list/... on an RSSHub instance where `READWISE_ACCESS_TOKEN` was never set. The check runs before any URLSearchParams parsing or API call.

Common situations: Self-hosted deploy that skipped the Readwise config block; user assumed the public rsshub.app instance ships with shared credentials (it does not — each user needs their own token); token name typo in env (`READWISE_TOKEN` instead of `READWISE_ACCESS_TOKEN`).

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/4a92c827ca89c3b5. Report an issue: GitHub.