Skip to content

Troubleshooting

Fresh

Common problems and how to fix them.

Authentication Issues

"Unauthorized" error on every request (401)

Symptom: All API calls return 401 Unauthorized.

Check these in order:

  1. The Authorization header is present. Many HTTP clients require you to set headers explicitly — verify the header is being sent.
  2. The format is exactly Bearer YOUR_API_KEY:YOUR_API_SECRET — note the colon between key and secret, and the Bearer prefix with a space.
  3. The API Key and API Secret are correct. Log in to RSS.app and copy them directly — avoid manual retyping.
  4. There is no whitespace in the key or secret values. Environment variable parsing can sometimes include trailing newlines.

Debug by printing the raw header:

js
const key = process.env.RSSAPP_API_KEY;
const secret = process.env.RSSAPP_API_SECRET;
const token = `${key}:${secret}`;
console.log('Token length:', token.length);
console.log('Starts with expected prefix:', token.startsWith('your_expected_key_prefix'));

API works locally but not in production

Cause: Environment variables not set in the production environment.

Check that RSSAPP_API_KEY and RSSAPP_API_SECRET are configured in your production environment (Vercel environment variables, server .env, AWS Parameter Store, etc.). Environment variables defined in .env files are not automatically available in production deployments.


Feed Creation Issues

Creating a feed returns 409 Conflict

Cause: A feed for this URL already exists in your account.

Solutions:

  1. Use the List Feeds endpoint to find the existing feed
  2. Retrieve it by ID to get the current items
  3. If you want a fresh feed, delete the existing one first
js
// Find existing feed
const feeds = await getAllFeeds();
const existing = feeds.find((f) => f.source_url === yourUrl);
console.log('Existing feed ID:', existing?.id);

Feed is created but items array is empty

Possible causes:

  • The source website uses heavy JavaScript rendering. RSS.app processes the initial HTML response. Sites that require JavaScript execution to show content may not yield items immediately.
  • The URL requires authentication or is behind a paywall. RSS.app cannot access content that requires login.
  • The feed was just created and RSS.app is still processing the source. Wait a few minutes and retrieve the feed again.

Check:

js
const feed = await apiClient.get(`/feeds/${feedId}`).then((r) => r.data);
console.log('Is active:', feed.is_active);
console.log('Item count:', feed.items.length);

is_active is false

Cause: RSS.app could not successfully process the source URL.

Check that:

  • The URL is accessible without login from the public internet
  • The URL returns valid HTML (not a redirect loop, 404, or error page)
  • The URL uses HTTPS

Try opening the URL in an incognito browser window without any cookies or session state. If the page doesn't load in that context, RSS.app likely cannot access it either.


Pagination Issues

Getting duplicate results across pages

Cause: New items were inserted between page requests, causing the offset to shift.

Offset pagination can produce duplicates when the underlying dataset changes between requests. This is a known limitation of offset-based pagination with frequently updated data.

Mitigation: For syncing large datasets, fetch all pages quickly in sequence and deduplicate by id in your application:

js
const allFeeds = await getAllFeeds();
const unique = [...new Map(allFeeds.map((f) => [f.id, f])).values()];

Last page returns exact limit count but there are no more results

Cause: The total count is exactly divisible by your page size, so the last page has exactly limit items.

Handling: Make one more request. When you get an empty array, you know you've reached the end:

js
while (true) {
  const page = await fetchPage(limit, offset);
  allItems.push(...page);

  // Either condition signals end:
  if (page.length < limit || page.length === 0) break;
  offset += limit;
}

Webhook Issues

Webhook is configured but not firing

Check:

  1. The feed is active (is_active: true) — inactive feeds do not trigger webhooks
  2. The subscription scope is correct — if scoped to a bundle, the feed must be in that bundle
  3. The webhook URL is HTTPS and publicly accessible
  4. The source website has actually published new content since configuration

Test your endpoint manually:

js
// Simulate a webhook event
const axios = require('axios');

const testPayload = {
  id: 'evt_test_001',
  type: 'feed_update',
  feed: {
    id: 'feed_test',
    title: 'Test Feed',
    source_url: 'https://example.com',
    rss_feed_url: 'https://rss.app/feeds/test.xml',
    description: null,
    icon: null,
    is_active: true,
  },
  data: {
    items_new: [
      {
        url: 'https://example.com/article',
        title: 'Test Article',
        description_text: 'Test content',
        description_html: '<p>Test content</p>',
        thumbnail: null,
        authors: [{ name: 'Test Author' }],
        date_published: new Date().toISOString(),
      },
    ],
    items_changed: [],
  },
};

await axios.post('https://your-webhook-endpoint.com/webhooks/rssapp', testPayload);

Webhook endpoint returns 500 or times out

Cause: Handler is doing too much synchronous work before responding.

Always respond with 200 immediately and process the payload asynchronously:

js
app.post('/webhooks/rssapp', (req, res) => {
  // Respond FIRST
  res.status(200).json({ received: true });

  // Process AFTER
  processEvent(req.body).catch(console.error);
});

Receiving the same event multiple times

Cause: Your endpoint returned a non-200 status or timed out on a previous delivery, causing RSS.app to retry.

Implement idempotency using the event id:

js
const processedEventIds = new Set(); // Use a database in production

app.post('/webhooks/rssapp', (req, res) => {
  const event = req.body;

  res.status(200).json({ received: true });

  if (processedEventIds.has(event.id)) return;
  processedEventIds.add(event.id);

  processEvent(event).catch(console.error);
});

Rate Limiting

Hitting 429 errors during bulk operations

Cause: Creating or fetching many resources in rapid succession.

Add delays between requests or implement exponential backoff:

js
async function createFeedsWithBackoff(urls) {
  const results = [];

  for (const url of urls) {
    let delay = 500; // Start with 500ms between requests

    while (true) {
      try {
        const feed = await apiClient.post('/feeds', { url });
        results.push(feed.data);
        await new Promise((r) => setTimeout(r, delay));
        break;
      } catch (err) {
        if (err.response?.status === 429) {
          console.log(`Rate limited. Waiting ${delay}ms before retry.`);
          await new Promise((r) => setTimeout(r, delay));
          delay = Math.min(delay * 2, 10000); // Double up to 10s max
        } else {
          throw err;
        }
      }
    }
  }

  return results;
}

RSS.app API Documentation