{"record":{"id":"587884fc3bc3ff81","repo":"jackwener/OpenCLI","slug":"config-587884","errorCode":"CONFIG","errorMessage":"Missing Spotify credentials.\n\n1. Go to https://developer.spotify.com/dashboard and create an app\n2. Add http://127.0.0.1:8888/callback as a Redirect URI\n3. Copy your Client ID and Client Secret\n4. Open the file: ${envFile}\n5. Fill in SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET, then save\n6. Run: opencli spotify auth","messagePattern":"Missing Spotify credentials\\.\n\n1\\. Go to https://developer\\.spotify\\.com/dashboard and create an app\n2\\. Add http://127\\.0\\.0\\.1:8888/callback as a Redirect URI\n3\\. Copy your Client ID and Client Secret\n4\\. Open the file: (.+?)\n5\\. Fill in SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET, then save\n6\\. Run: opencli spotify auth","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/spotify/utils.js","lineNumber":38,"sourceCode":"        clientSecret: processEnv.SPOTIFY_CLIENT_SECRET || fileEnv.SPOTIFY_CLIENT_SECRET || '',\n    };\n}\nexport function isPlaceholderCredential(value) {\n    const normalized = value?.trim() || '';\n    if (!normalized)\n        return false;\n    return SPOTIFY_PLACEHOLDER_PATTERNS.some(pattern => pattern.test(normalized));\n}\nexport function hasConfiguredSpotifyCredentials(credentials) {\n    return Boolean(credentials.clientId.trim()) &&\n        Boolean(credentials.clientSecret.trim()) &&\n        !isPlaceholderCredential(credentials.clientId) &&\n        !isPlaceholderCredential(credentials.clientSecret);\n}\nexport function assertSpotifyCredentialsConfigured(credentials, envFile) {\n    if (hasConfiguredSpotifyCredentials(credentials))\n        return;\n    throw new CliError('CONFIG', `Missing Spotify credentials.\\n\\n` +\n        `1. Go to https://developer.spotify.com/dashboard and create an app\\n` +\n        `2. Add ${'http://127.0.0.1:8888/callback'} as a Redirect URI\\n` +\n        `3. Copy your Client ID and Client Secret\\n` +\n        `4. Open the file: ${envFile}\\n` +\n        `5. Fill in SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET, then save\\n` +\n        `6. Run: opencli spotify auth`);\n}\nexport function mapSpotifyTrackResults(data) {\n    const items = data?.tracks?.items;\n    if (!Array.isArray(items))\n        return [];\n    return items.map((track) => ({\n        track: track?.name || '',\n        artist: Array.isArray(track?.artists) ? track.artists.map((artist) => artist.name).join(', ') : '',\n        album: track?.album?.name || '',\n        uri: track?.uri || '',\n    }));\n}","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/spotify/utils.js#L20-L56","documentation":"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.","triggerScenarios":"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').","commonSituations":"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.","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"],"exampleFix":"// before (.env)\nSPOTIFY_CLIENT_ID=your_client_id_here\nSPOTIFY_CLIENT_SECRET=\n\n// after (.env)\nSPOTIFY_CLIENT_ID=4f2a9c8b1d3e4f5a6b7c8d9e0f1a2b3c\nSPOTIFY_CLIENT_SECRET=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6","handlingStrategy":"validation","validationCode":"import { readFileSync, existsSync } from 'node:fs';\n\nfunction spotifyCredentialsLookConfigured(envPath = '.env') {\n  if (!existsSync(envPath)) return { ok: false, reason: `${envPath} does not exist` };\n  const env = readFileSync(envPath, 'utf8');\n  const get = (k) => {\n    const m = env.match(new RegExp(`^${k}=(.*)$`, 'm'));\n    return m ? m[1].trim() : '';\n  };\n  const id = get('SPOTIFY_CLIENT_ID');\n  const secret = get('SPOTIFY_CLIENT_SECRET');\n  const placeholder = (v) => !v || /your_|placeholder|xxx|<.*>/i.test(v);\n  if (placeholder(id)) return { ok: false, reason: 'SPOTIFY_CLIENT_ID missing or placeholder' };\n  if (placeholder(secret)) return { ok: false, reason: 'SPOTIFY_CLIENT_SECRET missing or placeholder' };\n  return { ok: true };\n}\n// run before invoking any opencli spotify command","typeGuard":"function hasConfiguredSpotifyCredentials(c) {\n  return typeof c === 'object' && c !== null &&\n    typeof c.clientId === 'string' && c.clientId.length > 0 &&\n    typeof c.clientSecret === 'string' && c.clientSecret.length > 0 &&\n    !isPlaceholderCredential(c.clientId) &&\n    !isPlaceholderCredential(c.clientSecret);\n}","tryCatchPattern":"import { CliError } from '@jackwener/opencli/errors';\n\ntry {\n  await runSpotifyCommand(args);\n} catch (e) {\n  if (e instanceof CliError && e.code === 'CONFIG') {\n    console.error('Spotify not configured. Follow these steps:\\n' + e.message);\n    process.exitCode = 1;\n  } else {\n    throw e;\n  }\n}","preventionTips":["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)"],"tags":["config","spotify","oauth","missing-credentials","env-file"],"backgroundTag":"missing-env-var","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}