DIYgod/RSSHub · error · Error

Unable to locate Obsidian community search API config

Error message

Unable to locate Obsidian community search API config

What it means

Thrown when the regex extraction of the Obsidian community search API configuration fails. The `getSearchConfig` function fetches the HTML of `https://community.obsidian.md/search` and attempts to match two regex patterns: one for escaped JSON (`apiKey\":\"`) and one for unescaped JSON (`"apiKey":"`). If neither matches, the apiKey and Typesense URL cannot be extracted and the route cannot proceed.

Source

Thrown at lib/routes/obsidian/utils.ts:76

export function getTitle(path: string): string {
    const match = path.match(titleRegex);
    return match ? match[1] : '';
}

function getSearchPageUrl(type: CommunityEntryType) {
    const url = new URL(searchPageBaseUrl);
    url.searchParams.set('type', type);
    url.searchParams.set('sort', 'created');

    return url.href;
}

async function getSearchConfig(pageUrl: string): Promise<CommunitySearchConfig> {
    const html = await ofetch<string>(pageUrl);
    const match = html.match(/apiKey\\":\\"([^"\\]+)\\"[\s\S]*?url\\":\\"([^"\\]+)\\"/) ?? html.match(/"apiKey":"([^"]+)"[\s\S]*?"url":"([^"]+)"/);

    if (!match) {
        throw new Error('Unable to locate Obsidian community search API config');
    }

    return {
        apiKey: match[1],
        url: match[2].replaceAll(String.raw`\/`, '/'),
    };
}

function buildItem(document: CommunitySearchHit['document']): DataItem {
    return {
        title: document.name,
        description: document.short_desc,
        link: `https://community.obsidian.md/${document.type}s/${document.slug}`,
        guid: `${document.type}:${document.id}`,
        pubDate: document.github_created_at ? parseDate(document.github_created_at) : undefined,
        updated: document.latest_release_at ? parseDate(document.latest_release_at) : document.github_updated_at ? parseDate(document.github_updated_at) : undefined,
        author: document.authors?.join(', '),
        category: document.tags,

View on GitHub (pinned to bed535e087)

Solutions

  1. Open `https://community.obsidian.md/search?type=plugin&sort=created` in a browser and view the page source to find how the apiKey and search URL are currently embedded.
  2. Update the regex patterns on line 73 of `lib/routes/obsidian/utils.ts` to match the new HTML format.
  3. If the config is now loaded via a separate JS file or API call, refactor `getSearchConfig` to fetch from the new source.
  4. Check if the page returns a Cloudflare challenge and consider whether Puppeteer or a different fetch strategy is needed.

Example fix

// before
const match = html.match(/apiKey\\":\\"([^"\\]+)\\"[\s\S]*?url\\":\\"([^"\\]+)\\"/) ?? html.match(/"apiKey":"([^"]+)"[\s\S]*?"url":"([^"]+)"/);

// after — broader, order-independent matching
const apiKeyMatch = html.match(/"?apiKey"?\s*[:=]\s*"([^"]+)"/);
const urlMatch = html.match(/"?url"?\s*[:=]\s*"(https?:\\/\\/[^"]+)"/);
if (!apiKeyMatch || !urlMatch) {
    throw new Error('Unable to locate Obsidian community search API config');
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check: fetch the page and verify config is extractable before proceeding
const html = await ofetch<string>(pageUrl);
const hasConfig = /apiKey/.test(html) && /url/.test(html);
if (!hasConfig) {
    throw new Error('Obsidian community page does not contain expected search config markers');
}

Try / catch

try {
    const searchConfig = await getSearchConfig(pageUrl);
    // proceed with searchConfig...
} catch (e) {
    if (e instanceof Error && e.message.includes('Unable to locate')) {
        logger.error('Obsidian community HTML structure may have changed');
        // Optionally fall back to a known Typesense endpoint
    }
    throw e;
}

Prevention

When it happens

Trigger: The Obsidian community forum (Discourse) changed its HTML structure, removed the embedded search config, or changed the serialization format. The page loaded but the JSON blob containing apiKey/url was not present. A CDN or error page was returned instead of the real search page.

Common situations: Obsidian updated their Discourse instance and changed how the Typesense search config is embedded. The community page returned a Cloudflare challenge page instead of real HTML. The regex patterns are too rigid for the current JSON escaping variant.

Related errors


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