{"record":{"id":"f157a7b2c5e78aca","repo":"DIYgod/RSSHub","slug":"user-id-not-found","errorCode":null,"errorMessage":"User ID not found","messagePattern":"User ID not found","errorType":"exception","errorClass":"NotFoundError","httpStatus":404,"severity":"error","filePath":"lib/routes/threads/utils.ts","lineNumber":79,"sourceCode":"        const dom = new JSDOM(response);\n        const { document } = dom.window;\n\n        for (const el of document.querySelectorAll('script[data-sjs]')) {\n            try {\n                const data = JSONPath({\n                    path: '$..user_id',\n                    json: JSON.parse(el.textContent || ''),\n                });\n\n                if (data?.[0]) {\n                    return data[0];\n                }\n            } catch {\n                // Skip invalid JSON\n            }\n        }\n\n        throw new NotFoundError('User ID not found');\n    });\n\n    if (result) {\n        if (typeof result === 'string') {\n            return result;\n        }\n        if (typeof result === 'number') {\n            return result.toString();\n        }\n    }\n    throw new TypeError('Invalid user ID type');\n};\n\nconst hasMedia = (post) => post.image_versions2 || post.carousel_media || post.video_versions;\n\nconst buildMedia = (post) => {\n    let html = '';\n","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/threads/utils.ts#L61-L97","documentation":"Thrown by getUserId after iterating every `<script data-sjs>` tag on a Threads profile and finding no JSONPath `$..user_id` match. It means Threads did not embed the user id payload in the expected SJS scripts, so the cache factory function gives up with a NotFoundError.","triggerScenarios":"The Threads profile HTML has no `script[data-sjs]` elements carrying a `user_id` field, or all such scripts fail JSON.parse and fall into the catch on line 74. The result is cached (or not) and then surfaced to the caller.","commonSituations":"Threads shipped a new bundle that renames user_id, the profile does not exist (404 page still 200s with minimal HTML), or the response is a login/consent interstitial. A stale positive cache entry masking this is also possible but here the cache factory itself throws.","solutions":["Open the profile URL with the exact headers and inspect `script[data-sjs]` contents to confirm `user_id` is still present.","Broaden the JSONPath or add a fallback selector if Threads moved the id into a different script type.","Detect login/interstitial HTML early and throw a clearer error distinguishing 'profile not found' from 'page structure changed'.","Invalidate the cache key `threads:userId:{user}` if you previously stored a bad value."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const html = await ofetch(profileUrl(user), { headers });\nconst hasSjs = /<script[^>]*data-sjs[^>]*>/.test(html);\nif (!hasSjs) throw new Error('Threads profile page has no data-sjs scripts');","typeGuard":"const hasUserId = (o: unknown): boolean => JSONPath({ path: '$..user_id', json: o as object }).length > 0;","tryCatchPattern":"try { const id = await getUserId(user); /* use id */ }\ncatch (e) { if (e instanceof NotFoundError && /User ID/.test(e.message)) { /* surface as 404 or retry */ } else throw e; }","preventionTips":["Invalidate `threads:userId:{user}` after bundle changes","Distinguish 404 profile from layout change in error mapping","Pin the mobile UA that returns full SJS payload"],"tags":["scraping","threads","jsonpath","html-parsing","cache"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}