jackwener/OpenCLI · error · CliError
CONFIG
CONFIG
Error message
Missing Spotify credentials.
1. Go to https://developer.spotify.com/dashboard and create an app
2. Add http://127.0.0.1:8888/callback as a Redirect URI
3. Copy your Client ID and Client Secret
4. Open the file: ${envFile}
5. Fill in SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET, then save
6. Run: opencli spotify auth What it means
assertSpotifyCredentialsConfigured throws this CliError with code 'CONFIG' when the loaded Spotify credentials are absent or still placeholder values. The opencli Spotify integration requires a developer app's client ID/secret to run the OAuth flow, so it fails fast with step-by-step setup instructions instead of making doomed API calls. It only passes when hasConfiguredSpotifyCredentials finds non-placeholder clientId and clientSecret.
Source
Thrown at clis/spotify/utils.js:38
clientSecret: processEnv.SPOTIFY_CLIENT_SECRET || fileEnv.SPOTIFY_CLIENT_SECRET || '',
};
}
export function isPlaceholderCredential(value) {
const normalized = value?.trim() || '';
if (!normalized)
return false;
return SPOTIFY_PLACEHOLDER_PATTERNS.some(pattern => pattern.test(normalized));
}
export function hasConfiguredSpotifyCredentials(credentials) {
return Boolean(credentials.clientId.trim()) &&
Boolean(credentials.clientSecret.trim()) &&
!isPlaceholderCredential(credentials.clientId) &&
!isPlaceholderCredential(credentials.clientSecret);
}
export function assertSpotifyCredentialsConfigured(credentials, envFile) {
if (hasConfiguredSpotifyCredentials(credentials))
return;
throw new CliError('CONFIG', `Missing Spotify credentials.\n\n` +
`1. Go to https://developer.spotify.com/dashboard and create an app\n` +
`2. Add ${'http://127.0.0.1:8888/callback'} as a Redirect URI\n` +
`3. Copy your Client ID and Client Secret\n` +
`4. Open the file: ${envFile}\n` +
`5. Fill in SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET, then save\n` +
`6. Run: opencli spotify auth`);
}
export function mapSpotifyTrackResults(data) {
const items = data?.tracks?.items;
if (!Array.isArray(items))
return [];
return items.map((track) => ({
track: track?.name || '',
artist: Array.isArray(track?.artists) ? track.artists.map((artist) => artist.name).join(', ') : '',
album: track?.album?.name || '',
uri: track?.uri || '',
}));
}View on GitHub (pinned to 49907e53dc)
Solutions
- Create an app at https://developer.spotify.com/dashboard and add http://127.0.0.1:8888/callback as a Redirect URI
- Copy the Client ID and Client Secret into the env file shown in the error message as SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET, then save
- Run: opencli spotify auth
- Re-run your original command; ensure the values are real (no placeholder/sample text) so isPlaceholderCredential passes
Example fix
// before (.env) SPOTIFY_CLIENT_ID=your_client_id_here SPOTIFY_CLIENT_SECRET= // after (.env) SPOTIFY_CLIENT_ID=4f2a9c8b1d3e4f5a6b7c8d9e0f1a2b3c SPOTIFY_CLIENT_SECRET=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync, existsSync } from 'node:fs';
function spotifyCredentialsLookConfigured(envPath = '.env') {
if (!existsSync(envPath)) return { ok: false, reason: `${envPath} does not exist` };
const env = readFileSync(envPath, 'utf8');
const get = (k) => {
const m = env.match(new RegExp(`^${k}=(.*)$`, 'm'));
return m ? m[1].trim() : '';
};
const id = get('SPOTIFY_CLIENT_ID');
const secret = get('SPOTIFY_CLIENT_SECRET');
const placeholder = (v) => !v || /your_|placeholder|xxx|<.*>/i.test(v);
if (placeholder(id)) return { ok: false, reason: 'SPOTIFY_CLIENT_ID missing or placeholder' };
if (placeholder(secret)) return { ok: false, reason: 'SPOTIFY_CLIENT_SECRET missing or placeholder' };
return { ok: true };
}
// run before invoking any opencli spotify command Type guard
function hasConfiguredSpotifyCredentials(c) {
return typeof c === 'object' && c !== null &&
typeof c.clientId === 'string' && c.clientId.length > 0 &&
typeof c.clientSecret === 'string' && c.clientSecret.length > 0 &&
!isPlaceholderCredential(c.clientId) &&
!isPlaceholderCredential(c.clientSecret);
} Try / catch
import { CliError } from '@jackwener/opencli/errors';
try {
await runSpotifyCommand(args);
} catch (e) {
if (e instanceof CliError && e.code === 'CONFIG') {
console.error('Spotify not configured. Follow these steps:\n' + e.message);
process.exitCode = 1;
} else {
throw e;
}
} Prevention
- Create the .env from the repo's .env.example immediately after cloning
- Never commit placeholder values like your_client_id_here; fill real credentials before first use
- Add the http://127.0.0.1:8888/callback Redirect URI when creating the Spotify app
- Keep SPOTIFY_CLIENT_SECRET out of version control (.env in .gitignore)
When it happens
Trigger: Any opencli Spotify command calls assertSpotifyCredentialsConfigured(credentials, envFile); it throws when SPOTIFY_CLIENT_ID or SPOTIFY_CLIENT_SECRET is missing from the env file, empty, or matches the placeholder values detected by isPlaceholderCredential (e.g. copy-pasted sample values like 'your_client_id_here').
Common situations: Fresh clone of the repo without creating a .env file; created a Spotify app but never copied the credentials into the env file; left the template placeholder strings in place; wrote credentials to the wrong env file path; using a different Spotify account's app than expected.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- AUTH_REQUIRED
- REFRESH_FAILED
- AUTH_CORRUPTED
- Missing Xiaoyuzhou credentials. Expected ${filePath}
- delayMaxMs
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/587884fc3bc3ff81.
Report an issue: GitHub.