DIYgod/RSSHub · error · ConfigNotFoundError

Cannot get refresh token since MangaDex username or password

Error message

Cannot get refresh token since MangaDex username or password is not set

What it means

Thrown by `getAccessTokenByUserCredentials` (lib/routes/mangadex/_access.ts:57) as a `ConfigNotFoundError` when the client credentials ARE present but `config.mangadex.username` or `config.mangadex.password` is missing. This path is only taken when no refresh token is configured, so MangaDex is asked for a password grant — which needs the resource-owner credentials.

Source

Thrown at lib/routes/mangadex/_access.ts:57

                if (error instanceof FetchError && error.statusCode === 400) {
                    // If the refresh token is invalid, try to get a new one with the user credentials
                    return getAccessTokenByUserCredentials();
                }
                throw error;
            }
        },
        constants.TOKEN_EXPIRE,
        false
    );
};

const getAccessTokenByUserCredentials = async () => {
    if (!config.mangadex.clientId || !config.mangadex.clientSecret) {
        throw new ConfigNotFoundError('Cannot get access token since MangaDex client ID or secret is not set.');
    }

    if (!config.mangadex.username || !config.mangadex.password) {
        throw new ConfigNotFoundError('Cannot get refresh token since MangaDex username or password is not set');
    }

    const response = await got.post(constants.API.TOKEN, {
        headers: {
            'User-Agent': config.trueUA,
        },
        form: {
            grant_type: 'password',
            username: config.mangadex.username,
            password: config.mangadex.password,
            client_id: config.mangadex.clientId,
            client_secret: config.mangadex.clientSecret,
        },
    });

    const refreshToken = response?.data?.refresh_token;
    const accessToken = response?.data?.access_token;

View on GitHub (pinned to bed535e087)

Solutions

  1. Set `MANGADEX_USERNAME` and `MANGADEX_PASSWORD` to enable the password grant, OR
  2. Set `MANGADEX_REFRESH_TOKEN` so the password grant is never needed.
  3. Restart RSSHub after updating config.

Example fix

// before: client id/secret only
MANGADEX_CLIENT_ID=xxx
MANGADEX_CLIENT_SECRET=yyy

// after: add a refresh token (preferred) so username/password are unnecessary
MANGADEX_CLIENT_ID=xxx
MANGADEX_CLIENT_SECRET=yyy
MANGADEX_REFRESH_TOKEN=zzz
Defensive patterns

Strategy: validation

Validate before calling

function mangadexUserCredentialsConfigured(): boolean {
    return Boolean(config.mangadex?.username && config.mangadex?.password);
}
function mangadexRefreshTokenConfigured(): boolean {
    return Boolean(config.mangadex?.refreshToken);
}
// password grant is only valid when EITHER a refresh token OR user creds exist; client creds alone are insufficient.
if (!mangadexRefreshTokenConfigured() && !mangadexUserCredentialsConfigured()) {
    throw new Error('Set MANGADEX_REFRESH_TOKEN or (MANGADEX_USERNAME + MANGADEX_PASSWORD)');
}

Type guard

function hasMangadexUserCredentials(c: typeof config): c is typeof config & { mangadex: { username: string; password: string } } {
    return typeof c.mangadex?.username === 'string' && typeof c.mangadex?.password === 'string';
}

Try / catch

import ConfigNotFoundError from '@/errors/types/config-not-found';
try {
    return await getAccessTokenByUserCredentials();
} catch (e) {
    if (e instanceof ConfigNotFoundError && /username or password is not set/.test(e.message)) {
        return { disabled: true, reason: 'Set MANGADEX_REFRESH_TOKEN (preferred) or MANGADEX_USERNAME+MANGADEX_PASSWORD' };
    }
    throw e;
}

Prevention

When it happens

Trigger: Client id/secret set and no refresh token, but `MANGADEX_USERNAME`/`MANGADEX_PASSWORD` omitted; refresh token expired/invalid and the fallback to password grant finds no username/password.

Common situations: Admin intended to use refresh-token auth but never set it, leaving the password grant as the only path; credentials partially migrated.

Related errors


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