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

  1. Open /feeds/atom.xml directly and inspect the entry whose id matches the error message.
  2. If some entries legitimately lack a URL, skip them (return null and filter) instead of failing the whole feed.
  3. 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

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


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/bcd5aca2b4230e17. Report an issue: GitHub.