{"record":{"id":"58a702021e7eadf4","repo":"DIYgod/RSSHub","slug":"unexpected-title-please-open-an-issue","errorCode":null,"errorMessage":"Unexpected title, please open an issue.","messagePattern":"Unexpected title, please open an issue\\.","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":null,"severity":"error","filePath":"lib/routes/uptimerobot/rss.tsx","lineNumber":106,"sourceCode":"\nasync function handler(ctx) {\n    const id = ctx.req.param('id');\n    const routeParams = Object.fromEntries(new URLSearchParams(ctx.req.param('routeParams')));\n    const showID = fallback(undefined, queryToBoolean(routeParams.showID), true);\n\n    const rssUrl = `${rootURL}/${id}`;\n    const rss = await new Parser({\n        customFields: {\n            item: ['details:duration'],\n        },\n    }).parseURL(rssUrl);\n\n    const monitors = {};\n\n    const items = rss.items.toReversed().map((item) => {\n        const titleMatch = item.title!.match(titleRegex);\n        if (!titleMatch) {\n            throw new InvalidParameterError('Unexpected title, please open an issue.');\n        }\n        const [monitorName, status, id] = titleMatch.slice(1);\n\n        if (id !== item.link) {\n            throw new InvalidParameterError('Monitor ID mismatch, please open an issue.');\n        }\n\n        // id could be a URL, a domain, an IP address, or a hex string. fix it\n        let link;\n        try {\n            link = !id.startsWith('http') && id.includes('.') ? new URL(`http://${id}`).href : new URL(id).href;\n        } catch {\n            // ignore\n        }\n\n        const duration = item['details:duration'];\n        const monitor = (monitors[monitorName] ||= new Monitor(monitorName));\n","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/uptimerobot/rss.tsx#L88-L124","documentation":"An `InvalidParameterError` at lib/routes/uptimerobot/rss.tsx:106 when an RSS item's title fails to match `titleRegex = /(.*\\S)\\s+is\\s+([A-Z]+)\\s+\\((.+)\\)/`. The regex expects titles shaped like 'My Server is UP (example.com)'. If UptimeRobot changes their RSS title wording, spacing, or format, every item fails. The message 'open an issue' signals this is a format-drift detector, not a user input error.","triggerScenarios":"UptimeRobot updates their RSS title template (e.g. adds emoji, changes 'is' to 'has been', reorders fields); a monitor name itself contains ' is ' causing a greedy regex mismatch; the RSS feed ID (`:id` path param) is wrong and points to a different feed format.","commonSituations":"UptimeRobot ships a UI/RSS update; the monitor name has unusual characters; old `:id` from a deleted monitor now returns a generic feed.","solutions":["Fetch `https://rss.uptimerobot.com/{id}` directly in a browser and inspect the actual `<title>` tags to see the new format.","Update `titleRegex` at line 9 to match the current title wording.","Verify the `:id` path parameter is a valid UptimeRobot RSS feed identifier."],"exampleFix":"// before\nconst titleRegex = /(.*\\S)\\s+is\\s+([A-Z]+)\\s+\\((.+)\\)/;\n\n// after (example if UptimeRobot adds 'Status:' prefix)\nconst titleRegex = /(?:Status:\\s*)?(.*\\S)\\s+is\\s+([A-Z]+)\\s+\\((.+)\\)/;","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"const titleRegex = /(.*\\S)\\s+is\\s+([A-Z]+)\\s+\\((.+)\\)/;\nconst isExpectedTitle = (title: string): boolean => titleRegex.test(title);","tryCatchPattern":"try {\n    const items = parseUptimeRobotRss(rss);\n} catch (e) {\n    if (e instanceof InvalidParameterError && e.message.includes('Unexpected title')) {\n        // UptimeRobot RSS format changed — fetch raw feed and update titleRegex\n        console.error('UptimeRobot RSS title format drift detected; update titleRegex');\n    }\n    throw e;\n}","preventionTips":["Periodically fetch the raw UptimeRobot RSS feed to detect title format changes early.","Subscribe to UptimeRobot changelog/announcements for RSS format updates.","Make the title regex tolerant of minor wording changes (optional prefixes, flexible whitespace)."],"tags":["parsing","format-change","rss","uptimerobot"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}