{"record":{"id":"24a79508925a50c3","repo":"jackwener/OpenCLI","slug":"invalid-linkedin-learning-slug-slug","errorCode":null,"errorMessage":"Invalid LinkedIn Learning slug: \"${slug}\"","messagePattern":"Invalid LinkedIn Learning slug: \"(.+?)\"","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/linkedin-learning/course.js","lineNumber":31,"sourceCode":"        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;\n    }\n    if (!/^[a-zA-Z0-9-_]+$/.test(slug)) {\n        throw new ArgumentError(`Invalid LinkedIn Learning slug: \"${slug}\"`);\n    }\n    return slug;\n}\n\nfunction parseCourse(el, slug) {\n    const title = normalizeWhitespace(el?.title);\n    if (!title) return null;\n    const description = typeof el?.description === 'string'\n        ? el.description\n        : (el?.description?.text || '');\n    const duration = el?.duration?.unit === 'SECOND' ? String(el.duration.duration ?? '') : '';\n    const released = el?.activatedAt ? new Date(el.activatedAt).toISOString().slice(0, 10) : '';\n    return {\n        title,\n        slug,\n        description,\n        difficulty: el?.difficultyLevel || '',\n        duration_sec: duration,","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin-learning/course.js#L13-L49","documentation":"Thrown by parseSlug after a slug is extracted (from a URL, a /learning/<slug> path, or the raw input) when it fails the ^[a-zA-Z0-9-_]+$ check. LinkedIn Learning slugs are ASCII letters, digits, hyphens, and underscores only, so characters like spaces, dots, slashes, or non-Latin scripts indicate a malformed identifier.","triggerScenarios":"Calling the linkedin-learning course command with a slug containing '.' (e.g. 'agentic.ai'), '/', '?', unicode characters, or trailing punctuation; also non-ASCII localized course titles used as identifiers.","commonSituations":"Quoting/parsing mistakes that leave URL fragments or query strings attached; copying the localized title rather than the slug from the address bar; course IDs like 'urn:li:course:123' pasted directly.","solutions":["Pass the ASCII slug exactly as it appears in the /learning/<slug> URL, stripped of query strings, fragments, and trailing slashes.","Pass the full canonical https://www.linkedin.com/learning/<slug>/ URL instead of hand-editing the slug.","Look up the course via the linkedin-learning search command to obtain the correct slug."],"exampleFix":"// before\nopencli linkedin-learning course 'agentic.ai?trk=feed'\n// after\nopencli linkedin-learning course 'agentic-ai-build-your-first-agentic-ai-system'","handlingStrategy":"validation","validationCode":"const SLUG_RE = /^[a-zA-Z0-9-_]+$/;\nif (!SLUG_RE.test(slugOrExtractedSlug)) {\n  throw new Error(`Bad slug before call: \"${slugOrExtractedSlug}\"`);\n}","typeGuard":"function isValidSlug(v) {\n  return typeof v === 'string' && /^[a-zA-Z0-9-_]+$/.test(v);\n}","tryCatchPattern":"try {\n  run(['linkedin-learning', 'course', slug]);\n} catch (e) {\n  if (String(e.message).includes('Invalid LinkedIn Learning slug')) {\n    // strip query/fragment/unicode, or resolve via search, then retry\n  } else throw e;\n}","preventionTips":["Strip query strings, fragments, and trailing slashes from anything copied from the address bar.","Never pass URNs (urn:li:course:...) or localized titles as slugs.","Obtain slugs from the search command's url column instead of hand-typing them."],"tags":["argument-validation","slug","linkedin-learning"],"backgroundTag":"invalid-identifier-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}