DIYgod/RSSHub · error · Error

failed to parse AJAX response

Error message

failed to parse AJAX response

What it means

The Prime Minister of Canada site uses Drupal's Views AJAX module, which returns an array of command objects (each with a method like replaceWith, insert, etc.). The route finds the entry whose method is 'replaceWith' to obtain the HTML fragment. If none exists, the AJAX response shape changed (Drupal core update, view renamed, or an error body was returned), and the route cannot proceed.

Source

Thrown at lib/routes/gc.ca/pm-news.ts:44

    ],
    name: 'News',
    maintainers: ['elibroftw'],
    handler: async (ctx: Context): Promise<Data> => {
        const { language = 'en' } = ctx.req.param();

        const ajaxURL = language === 'fr' ? 'https://www.pm.gc.ca/fr/views/ajax' : 'https://www.pm.gc.ca/views/ajax';

        const response = await ofetch(ajaxURL, {
            method: 'post',
            body: new URLSearchParams({ view_name: 'news', view_display_id: 'page_1', view_args: '', page: '0' }).toString(),
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
        });

        const replaceItem = response.find((item: any) => item.method === 'replaceWith');
        if (!replaceItem) {
            throw new Error('failed to parse AJAX response');
        }

        const $ = load(replaceItem.data);
        const items: DataItem[] = $('.news-row')
            .toArray()
            .map((element) => {
                const $element = $(element);
                const $titleLink = $element.find('.title a');
                const $category = $element.find('.category');
                const $date = $element.find('.location-date time');

                const title = $titleLink.text().trim();
                const link = $titleLink.attr('href')!;
                const category = $category.text().trim();
                const date = $date.attr('datetime') || '';

                if (title && link) {
                    return {

View on GitHub (pinned to bed535e087)

Solutions

  1. POST to the ajaxURL manually (with the same form body) and inspect the raw JSON to see what methods/commands are present.
  2. If the view was renamed, update view_name/view_display_id to match the current site.
  3. If the replaceWith command moved, adjust the find() predicate or fall back to another command carrying the HTML.
  4. Switch to scraping the news page HTML directly if the AJAX layer is unstable.

Example fix

// before
const replaceItem = response.find((item: any) => item.method === 'replaceWith');
if (!replaceItem) {
    throw new Error('failed to parse AJAX response');
}

// after
const replaceItem = response.find((item: any) => item.method === 'replaceWith');
if (!replaceItem) {
    const methods = Array.isArray(response) ? response.map((i) => i?.method).join(', ') : 'non-array response';
    throw new Error(`failed to parse AJAX response. Observed methods: ${methods}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

import ofetch from '@/utils/ofetch';
const probe = await ofetch(ajaxURL, { method: 'post', body: new URLSearchParams({ view_name: 'news', view_display_id: 'page_1', view_args: '', page: '0' }).toString(), headers: { 'Content-Type': 'application/x-www-form-urlencoded' } });
if (!Array.isArray(probe) || !probe.some((i) => i?.method === 'replaceWith')) {
  throw new Error('Drupal AJAX shape changed; inspect raw response');
}

Type guard

const hasReplaceWith = (res: unknown): res is Array<{ method: string; data: string }> =>
  Array.isArray(res) && res.some((i: any) => i?.method === 'replaceWith' && typeof i.data === 'string');

Try / catch

try {
  const replaceItem = response.find((item: any) => item.method === 'replaceWith');
  if (!replaceItem) throw new Error('failed to parse AJAX response');
} catch (e) {
  // fall back to scraping the news page HTML directly
  throw e;
}

Prevention

When it happens

Trigger: pm.gc.ca upgrades Drupal and changes the AJAX command structure; the 'news' view or 'page_1' display is renamed/removed; the endpoint returns an error JSON without command objects; the view_args or view_display_id no longer match the deployed view.

Common situations: Drupal major-version upgrades; site redesigns renaming the news view; locale differences (fr vs en endpoint) returning different structures; caching layers stripping the response.

Understand the failure class

Related errors


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