{"record":{"id":"13d856247445dcee","repo":"jackwener/OpenCLI","slug":"slug-is-required","errorCode":null,"errorMessage":"<slug> is required","messagePattern":"<slug> is required","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/linkedin-learning/course.js","lineNumber":10,"sourceCode":"/**\n * LinkedIn Learning course detail by slug, via /learning-api/courses?q=slug.\n */\nimport { cli, Strategy } from '@jackwener/opencli/registry';\nimport { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\nimport { DOMAIN, fetchLinkedInLearningApi, normalizeWhitespace } from './shared.js';\n\nfunction parseSlug(value) {\n    const s = normalizeWhitespace(value);\n    if (!s) throw new ArgumentError('<slug> is required');\n    let slug = s;\n    if (/^https?:\\/\\//i.test(s)) {\n        let parsed;\n        try {\n            parsed = new URL(s);\n        } catch {\n            throw new ArgumentError(`Invalid LinkedIn Learning URL: \"${s}\"`);\n        }\n        const host = parsed.hostname.toLowerCase();\n        if (host !== 'linkedin.com' && host !== 'www.linkedin.com') {\n            throw new ArgumentError(`Invalid LinkedIn Learning host: \"${parsed.hostname}\"`);\n        }\n        const m = parsed.pathname.match(/^\\/learning\\/([^/?#]+)/);\n        if (!m) throw new ArgumentError(`Invalid LinkedIn Learning course URL: \"${s}\"`);\n        slug = m[1];\n    } else {\n        const m = s.match(/^\\/?learning\\/([^/?#]+)/);\n        slug = m ? m[1] : s;","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin-learning/course.js#L1-L28","documentation":"parseSlug normalizes the user-supplied slug/URL argument with normalizeWhitespace and throws ArgumentError if the result is empty. It's the standard 'required argument missing' guard for linkedin-learning course commands, ensuring downstream URL/slug parsing always has a value.","triggerScenarios":"Calling the course command with an empty string, whitespace-only value, or missing positional argument so normalizeWhitespace(value) yields ''.","commonSituations":"Shell variable holding the slug was empty/unset; extra quoting consumed the argument; user ran the command with the flag but forgot the value; copy-paste captured only whitespace.","solutions":["Pass a non-empty course slug or LinkedIn Learning URL to the command.","Check the shell variable actually has a value (echo \"$SLUG\") before invoking.","Quote the argument if it contains special characters.","Verify command usage with --help and supply the required <slug> positional."],"exampleFix":"// before\nrun(['linkedin-learning', 'course', slug]); // slug = ''\n// after\nif (!slug?.trim()) throw new Error('slug required');\nrun(['linkedin-learning', 'course', slug.trim()]);","handlingStrategy":"validation","validationCode":"const slug = (process.argv[3] ?? '').trim();\nif (!slug) {\n  console.error('usage: linkedin-learning course <slug-or-url>');\n  process.exit(2);\n}","typeGuard":"function hasSlug(v) { return typeof v === 'string' && v.trim().length > 0; }","tryCatchPattern":"try {\n  await runCommand(['linkedin-learning', 'course', slug]);\n} catch (e) {\n  if (e.name === 'ArgumentError' && e.message.includes('is required')) {\n    console.error('usage: linkedin-learning course <slug-or-url>');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Check shell variables are non-empty before interpolating into commands.","Quote arguments to avoid whitespace collapse.","Print usage help when a positional argument is absent.","Trim inputs before passing to CLI commands."],"tags":["arguments","validation","cli"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}