can1357/oh-my-pi · error

ClinePass model catalog response is missing clinePass

Error message

ClinePass model catalog response is missing clinePass

What it means

After a successful (ok) fetch, the ClinePass mapper validates the JSON payload shape: it must be a record containing a `clinePass` array. This throw means the server returned 200 but the body is not the expected catalog shape, so parsing is aborted rather than producing zero models.

Source

Thrown at packages/catalog/src/provider-models/openai-compat.ts:2690

async function fetchClinePassModels(
	fetchImpl: FetchImpl,
	references: ReadonlyMap<string, ModelSpec<"openai-completions">>,
): Promise<ModelSpec<"openai-completions">[]> {
	// The roster is authoritative for ids; the live reference catalog is a pure
	// enrichment tier fetched alongside and tolerated away (offline → bundle).
	const [response, liveCatalog] = await Promise.all([
		withCatalogDiscoveryTimeout(5_000, signal =>
			fetchImpl(CLINEPASS_MODELS_URL, { signal, headers: clinePassClientHeaders() }),
		),
		fetchClinePassLiveCatalog(fetchImpl),
	]);
	if (!response.ok) {
		throw new Error(`Failed to fetch ClinePass models: HTTP ${response.status}`);
	}
	const payload: unknown = await response.json();
	if (!isRecord(payload) || !Array.isArray(payload.clinePass)) {
		throw new Error("ClinePass model catalog response is missing clinePass");
	}

	const models = new Map<string, ModelSpec<"openai-completions">>();
	for (const entry of payload.clinePass) {
		if (!isRecord(entry) || typeof entry.id !== "string") {
			continue;
		}
		const wireId = entry.id.trim();
		if (!wireId.startsWith("cline-pass/")) {
			continue;
		}
		const id = toClinePassPublicModelId(wireId).trim();
		if (!id) {
			continue;
		}
		models.set(id, buildClinePassSubscriptionModel(id, references, liveCatalog));
	}
	if (models.size === 0) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Log/inspect the actual response body to see what changed
  2. Update the catalog package to match the current ClinePass API schema
  3. Verify the request is authenticated so the real catalog (not a portal page) is returned
  4. Bypass proxies/caches to rule out a stale cached 200 response
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetch(CLINEPASS_MODELS_URL, { headers: clinePassClientHeaders() });
const payload = await res.json();
if (!(payload && typeof payload === "object") || !Array.isArray(payload.clinePass)) {
  throw new Error("Unexpected ClinePass response shape");
}

Type guard

function isClinePassCatalog(payload: unknown): payload is { clinePass: { id: string }[] } {
  return typeof payload === "object" && payload !== null
    && Array.isArray((payload as { clinePass?: unknown }).clinePass);
}

Try / catch

try {
  models = await fetchClinePassModels();
} catch (err) {
  if (err instanceof Error && err.message.includes("missing clinePass")) {
    logger.warn("ClinePass schema changed; falling back to cached catalog", { cause: err });
    return cachedModels;
  }
  throw err;
}

Prevention

When it happens

Trigger: ClinePass /models endpoint returns 200 with a JSON body lacking `clinePass` or where `clinePass` is not an array (API contract change, HTML login page served with 200, empty placeholder).

Common situations: ClinePass API schema version drift, hitting an auth/portal URL that returns 200 HTML, an edge proxy serving a cached empty response.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/2fd779fa30c2c6c7. Report an issue: GitHub.