{"record":{"id":"c0d93f232a9732ba","repo":"jackwener/OpenCLI","slug":"url-must-be-on-tiktok-com-got-parsed-hostname","errorCode":null,"errorMessage":"URL must be on tiktok.com (got ${parsed.hostname})","messagePattern":"URL must be on tiktok\\.com \\(got (.+?)\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/tiktok/utils.js","lineNumber":122,"sourceCode":"export function parseTikTokVideoUrl(value) {\n    const raw = String(value ?? '').trim();\n    if (!raw) {\n        throw new ArgumentError(\n            'video URL is required',\n            'Example: opencli tiktok comment https://www.tiktok.com/@user/video/1234567890 \"...\"',\n        );\n    }\n    let parsed;\n    try {\n        parsed = new URL(raw);\n    } catch {\n        throw new ArgumentError(\n            `invalid video URL: ${raw}`,\n            'Example: https://www.tiktok.com/@user/video/1234567890',\n        );\n    }\n    if (!/(^|\\.)tiktok\\.com$/i.test(parsed.hostname)) {\n        throw new ArgumentError(\n            `URL must be on tiktok.com (got ${parsed.hostname})`,\n            'Example: https://www.tiktok.com/@user/video/1234567890',\n        );\n    }\n    const match = parsed.pathname.match(/^\\/@([A-Za-z0-9._-]+)\\/video\\/(\\d+)\\/?$/);\n    if (!match) {\n        throw new ArgumentError(\n            'URL must follow /@<username>/video/<id> format',\n            'Example: https://www.tiktok.com/@user/video/1234567890',\n        );\n    }\n    return {\n        url: parsed.toString(),\n        username: match[1],\n        videoId: match[2],\n    };\n}\n","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/utils.js#L104-L140","documentation":"After successful URL parsing, parseTikTokVideoUrl verifies the hostname matches /(^|\\.)tiktok\\.com$/i. Any other host (or an exact-looking decoy domain) is rejected with the offending hostname in the message.","triggerScenarios":"Passing a valid URL whose hostname is not tiktok.com or a subdomain of it — e.g. youtube.com links, typos like tiktok.com.evil.io (rejected by the anchored regex), or tiktokcom without the dot.","commonSituations":"Extracting a link from a playlist of mixed-platform URLs; typo'd domains; redirector/shortener hosts; pasting a Douyin URL.","solutions":["Use a URL on tiktok.com or a *.tiktok.com subdomain","Resolve shorteners to their final tiktok.com destination before calling","Check the pasted domain for typos (tikok.com, tiktok.org, etc.)"],"exampleFix":"// before\nparseTikTokVideoUrl('https://example.com/video/123')\n// after\nparseTikTokVideoUrl('https://www.tiktok.com/@user/video/123')","handlingStrategy":"validation","validationCode":"const h = new URL(value).hostname; if (!/(^|\\.)tiktok\\.com$/i.test(h)) throw new Error(`not a tiktok.com URL: ${h}`);","typeGuard":"const isTikTokUrl = (v) => { try { return /(^|\\.)tiktok\\.com$/i.test(new URL(String(v)).hostname); } catch { return false; } };","tryCatchPattern":"try { parseTikTokVideoUrl(url); } catch (e) { if (/URL must be on tiktok\\.com/.test(e.message)) console.error('Only tiktok.com hosts are supported'); else throw e; }","preventionTips":["Filter mixed-platform link lists by hostname before processing","Resolve shorteners/redirectors before validating","Watch for typosquatted domains in user-supplied input"],"tags":["validation","url-parsing","domain-validation"],"backgroundTag":"invalid-url-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}