DIYgod/RSSHub · warning · Error
No article URL found for article with id ${id}
Error message
No article URL found for article with id ${id} What it means
Thrown by tailwindcss/utils.ts:36 via `throw new Error(...)` (NOT an InvalidParameterError) when a Tailwind CSS Atom feed <entry> has no <link href=...> element. The route fetches /feeds/atom.xml, iterates entries, and takes the first link[href] as the article URL; an entry whose link elements lack href (or has none at all) triggers this. It is mostly a guard against malformed/partial feed entries.
Source
Thrown at lib/routes/tailwindcss/utils.ts:36
export const fetchFeed = async (limit: number): Promise<Data> => {
const url = new URL('/feeds/atom.xml', BASE_URL).href;
const data = await ofetch(url, { responseType: 'text' });
const $ = load(data, { xml: true });
const items = await Promise.all(
$('entry')
.toArray()
.slice(0, limit)
.map((entry) => {
const title = $(entry).find('title').text();
const id = $(entry).find('id').text();
const url = $(entry).find('link[href]').attr('href');
const imageUrl = $(entry).find('link[rel="enclosure"]').attr('href');
if (url === undefined) {
throw new Error(`No article URL found for article with id ${id}`);
}
return cache.tryGet(
`tailwindcss:${id}`,
async () =>
({
title,
link: url,
image: imageUrl,
description: await fetchArticleContent(url),
author: $(entry)
.find('author')
.toArray()
.map((el) => ({
name: $(el).find('name').text(),
url: $(el).find('url').text(),
})),
pubDate: $(entry).find('updated').text(),View on GitHub (pinned to bed535e087)
Solutions
- Open /feeds/atom.xml directly and inspect the entry whose id matches the error message.
- If some entries legitimately lack a URL, skip them (return null and filter) instead of failing the whole feed.
- If the link moved to a different attribute/rel, update the selector (e.g. link[rel="alternate"]).
Example fix
// before
if (url === undefined) {
throw new Error(`No article URL found for article with id ${id}`);
}
// after (skip entries without a URL so the feed stays up)
if (url === undefined) {
return null;
}
// then: .filter(Boolean) on the collected items Defensive patterns
Strategy: validation
Validate before calling
// Filter entries lacking a usable URL before mapping.
const usableEntries = $('entry').toArray().filter((entry) =>
$(entry).find('link[href]').attr('href') !== undefined
); Type guard
function entryHasUrl($entry: ReturnType<typeof load>): $entry is ReturnType<typeof load> {
return $entry.find('link[href]').attr('href') !== undefined;
} Try / catch
// Wrap per-entry processing so one malformed entry does not fail the feed.
const items = await Promise.all(
entries.map(async (entry) => {
try {
return await buildItem(entry);
} catch (e) {
if (e instanceof Error && /No article URL found/.test(e.message)) return null;
throw e;
}
})
).then((arr) => arr.filter(Boolean)); Prevention
- Inspect /feeds/atom.xml directly when this fires to see the offending entry.
- Consider skipping entries without a URL (return null + filter) instead of throwing.
- Update the link selector if Tailwind moves the URL to a different rel/attribute.
When it happens
Trigger: Tailwind's feed format changes; an entry is a non-article type (category/page) with no canonical link; the feed is partially generated or broken upstream.
Common situations: Feed schema change after a docs-site rebuild; a transient partial feed; a CMS-added entry that lacks a URL.
Related errors
- Cannot get the redirect link
- TechFlow API returned an unexpected non-JSON response.
- Unable to decode the Locals server response.
- Unable to resolve the Locals community metadata.
- Unable to locate the current Locals serverApi asset.
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/bcd5aca2b4230e17.
Report an issue: GitHub.