jackwener/OpenCLI · error · CommandExecutionError
Substack publication search failed: HTTP ${resp.status}
Error message
Substack publication search failed: HTTP ${resp.status} What it means
searchPublications calls the Substack profile/publication search API (substack.com/api/v1/profile/search). Any non-ok HTTP response throws a CommandExecutionError carrying the status code.
Source
Thrown at clis/substack/search.js:44
throw new CommandExecutionError(`Substack post search failed: HTTP ${resp.status}`);
const data = await resp.json();
const results = Array.isArray(data?.results) ? data.results : [];
return results.slice(0, limit).map((item, index) => ({
rank: index + 1,
title: trim(item?.title),
author: trim(item?.publishedBylines?.[0]?.name),
date: trim(item?.post_date).split('T')[0] || trim(item?.post_date),
description: trim(item?.description || item?.subtitle || item?.truncated_body_text).slice(0, 150),
url: trim(item?.canonical_url),
}));
}
async function searchPublications(keyword, limit) {
const url = new URL('https://substack.com/api/v1/profile/search');
url.searchParams.set('query', keyword);
url.searchParams.set('page', '0');
const resp = await fetch(url, { headers: headers() });
if (!resp.ok)
throw new CommandExecutionError(`Substack publication search failed: HTTP ${resp.status}`);
const data = await resp.json();
const results = Array.isArray(data?.results) ? data.results : [];
return results.slice(0, limit).map((item, index) => {
const publication = item?.primaryPublication || item?.publicationUsers?.[0]?.publication || {};
return {
rank: index + 1,
title: trim(publication?.name || item?.name),
author: trim(item?.name),
date: '',
description: trim(publication?.hero_text || item?.bio).slice(0, 150),
url: publicationBaseUrl(publication),
};
});
}
cli({
site: 'substack',
name: 'search',
access: 'read',View on GitHub (pinned to 49907e53dc)
Solutions
- Retry with backoff for transient 429/5xx statuses
- Run within a browser session so request headers include valid cookies
- Reduce lookup frequency or batch size
- Confirm the endpoint path is still valid after Substack API updates
Example fix
// before
const pubs = await searchPublications('tech', 10); // throws on 403
// after
let pubs;
try { pubs = await searchPublications('tech', 10); }
catch (e) { console.error('publication search:', e.message); pubs = []; } Defensive patterns
Strategy: retry
Validate before calling
// ensure a browser session exists so headers() carries valid cookies
if (!session || !session.cookies) throw new Error('run within a browser session for substack publication search'); Type guard
null
Try / catch
try { pubs = await searchPublications(q, 10); } catch (e) {
const m = /HTTP (\d+)/.exec(e.message);
if (m && ['429','502','503'].includes(m[1])) { await sleep(5000); pubs = await searchPublications(q, 10); } else throw e;
} Prevention
- Throttle bulk publication lookups
- Run inside a browser session for valid cookies
- Retry transient 5xx with backoff
- Verify endpoint paths after Substack updates
When it happens
Trigger: Any searchPublications call where the profile search endpoint returns non-2xx: rate limiting, missing session cookies, 403 from bot protection, or 5xx during Substack incidents.
Common situations: Bulk publication lookups in a loop, unauthenticated calls from datacenter IPs, Substack API surface changes, transient 502/503 during platform deploys.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Substack post search failed: HTTP ${resp.status}
- HTTP ' + res.status + ' - make sure you are logged in to Ins
- NOT_FOUND
- Detached HEAD — checkout a branch first
- No 12306 stations match "${keyword}"
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/99ef0f2dc07cbbe5.
Report an issue: GitHub.