jackwener/OpenCLI · error · ConfigError
Missing Xiaoyuzhou credentials. Expected ${filePath}
Error message
Missing Xiaoyuzhou credentials. Expected ${filePath} What it means
Thrown by loadXiaoyuzhouCredentials when the credential file ~/.opencli/xiaoyuzhou.json does not exist on disk. The library stores Xiaoyuzhou (小宇宙) app access_token and refresh_token in that file and refuses to call the API without them, raising a ConfigError. It means setup, not a runtime bug: the client has never been authenticated.
Source
Thrown at clis/xiaoyuzhou/auth.js:65
export function loadXiaoyuzhouCredentials() {
const filePath = getXiaoyuzhouCredentialFile();
if (fs.existsSync(filePath)) {
try {
const parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
const credentials = normalizeXiaoyuzhouCredentials(parsed);
if (!credentials.access_token || !credentials.refresh_token) {
throw new ConfigError(`Xiaoyuzhou credential file is missing access_token or refresh_token: ${filePath}`, 'Recreate the file with valid credentials.');
}
return credentials;
}
catch (error) {
if (error instanceof ConfigError) {
throw error;
}
throw new ConfigError(`Failed to parse Xiaoyuzhou credential file: ${filePath}`, `Ensure ${filePath} contains valid JSON. (${getErrorMessage(error)})`);
}
}
throw new ConfigError(`Missing Xiaoyuzhou credentials. Expected ${filePath}`, `Create ${filePath} with access_token and refresh_token.`);
}
export function saveXiaoyuzhouCredentials(credentials) {
const filePath = getXiaoyuzhouCredentialFile();
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, `${JSON.stringify({
access_token: credentials.access_token,
refresh_token: credentials.refresh_token,
expires_at: credentials.expires_at,
device_id: credentials.device_id,
device_properties: credentials.device_properties,
}, null, 2)}\n`, 'utf-8');
}
export function shouldRefreshXiaoyuzhouCredentials(credentials, now = getNowMs()) {
return Number.isFinite(credentials.expires_at)
&& credentials.expires_at > 0
&& now >= credentials.expires_at - XIAOYUZHOU_REFRESH_SKEW_MS;View on GitHub (pinned to 49907e53dc)
Solutions
- Create ~/.opencli/xiaoyuzhou.json containing at least {"access_token":"...","refresh_token":"..."} (tokens captured from the Xiaoyuzhou app).
- Verify you are running as the same user/$HOME that owns the credential file: echo $HOME and check ls ~/.opencli/xiaoyuzhou.json.
- In CI/Docker, mount or inject the credential file (e.g. copy ~/.opencli/xiaoyuzhou.json into the image or a volume).
- Alternatively pass credentials explicitly via requestXiaoyuzhouJson(endpoint, { credentials }) to bypass the file entirely.
Example fix
// before: running any command without credentials -> ConfigError
$ opencli xiaoyuzhou episode <id>
// after: create the expected credential file
$ mkdir -p ~/.opencli
$ cat > ~/.opencli/xiaoyuzhou.json <<'EOF'
{
"access_token": "<token-from-app>",
"refresh_token": "<refresh-token-from-app>"
}
EOF Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
const credFile = path.join(os.homedir(), '.opencli', 'xiaoyuzhou.json');
if (!fs.existsSync(credFile)) {
throw new Error(`Run auth setup first: ${credFile} is missing (needs access_token + refresh_token).`);
}
const creds = JSON.parse(fs.readFileSync(credFile, 'utf-8'));
if (!creds.access_token || !creds.refresh_token) {
throw new Error(`${credFile} is missing access_token or refresh_token.`);
} Type guard
function hasXiaoyuzhouCredentials(value) {
return typeof value === 'object' && value !== null
&& typeof value.access_token === 'string' && value.access_token.length > 0
&& typeof value.refresh_token === 'string' && value.refresh_token.length > 0;
} Try / catch
import { ConfigError } from '@jackwener/opencli/errors';
try {
await requestXiaoyuzhouJson('/episodes/get', { query: { eid } });
} catch (err) {
if (err instanceof ConfigError && err.message.startsWith('Missing Xiaoyuzhou credentials')) {
console.error(`No credentials configured. Create ${err.message.match(/Expected (\S+)/)?.[1]} first.`);
process.exitCode = 1;
return;
}
throw err;
} Prevention
- Run a preflight check (fs.existsSync on ~/.opencli/xiaoyuzhou.json) at CLI startup before any API call.
- Pin the credential path in setup docs and scripts; never assume $HOME — in Docker/CI mount the file explicitly.
- Keep a bootstrap script that writes the credential file from environment variables on first run.
- Don't delete or rename the ~/.opencli directory during cleanup operations.
When it happens
Trigger: Any call to requestXiaoyuzhouJson (e.g. episode, transcript, or history endpoints) without options.credentials when ~/.opencli/xiaoyuzhou.json is absent — the common case being the very first use of any xiaoyuzhou CLI command on a fresh machine or in a container/CI where HOME points elsewhere.
Common situations: Fresh install before running any auth setup; running the CLI as a different user (or with a different $HOME) than the one that saved credentials; Docker images or CI runners where the dotfile was never copied; accidentally deleted or renamed ~/.opencli directory.
Related errors
- AUTH_REQUIRED
- CONFIG
- Verify command returned no metric for baseline
- 12306 tk auth cookie missing
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/19c63b504153e6c4.
Report an issue: GitHub.