linshenkx/prompt-optimizer · error · APIError

Cloudflare model search returned an unexpected response form

Error message

Cloudflare model search returned an unexpected response format

What it means

Cloudflare's model search endpoint returned HTTP 200 but the JSON body failed the shape check: it must have success===true and result as an array. The adapter treats this as an unexpected contract violation rather than trying to read fields from it.

Source

Thrown at packages/core/src/services/llm/adapters/cloudflare-adapter.ts:80

  public async getModelsAsync(config: TextModelConfig): Promise<TextModel[]> {
    const accountId = this.getAccountId(config);
    const baseURL = this.resolveCloudflareManagementBaseURL(config.connectionConfig.baseURL, accountId);
    const url = `${baseURL}/models/search?task=${encodeURIComponent('Text Generation')}&hide_experimental=true&per_page=100`;

    const response = await fetch(url, {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${config.connectionConfig.apiKey || ''}`
      }
    });

    if (!response.ok) {
      throw new APIError(`Cloudflare model search failed: ${await this.getErrorMessage(response)}`);
    }

    const data = await response.json();
    if (!data?.success || !Array.isArray(data?.result)) {
      throw new APIError('Cloudflare model search returned an unexpected response format');
    }

    const models = data.result
      .filter((model: CloudflareModelSearchResult) => {
        return model?.task?.name === 'Text Generation' && typeof model?.name === 'string' && !!model.name.trim();
      })
      .map((model: CloudflareModelSearchResult) => this.mapDynamicModel(model));

    return models.length > 0 ? models : this.getModels();
  }

  public getModels(): TextModel[] {
    return CLOUDFLARE_STATIC_MODELS.map((definition) => {
      const baseModel = this.buildDefaultModel(definition.id);

      return {
        ...baseModel,
        name: definition.name,

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. curl the model search URL manually and inspect the payload for { success, result }
  2. Remove custom base URL overrides so the adapter uses the default Cloudflare endpoint
  3. Upgrade the package if Cloudflare changed the schema and a fix shipped
  4. Fall back to a static list of Cloudflare models in the UI when this format error occurs

Example fix

// before
const models = await adapter.getModelsAsync()

// after
let models
try { models = await adapter.getModelsAsync() }
catch (e) {
  if (e instanceof APIError && e.message.includes('unexpected response format')) {
    models = DEFAULT_CLOUDFLARE_MODELS
  } else throw e
}
Defensive patterns

Strategy: fallback

Validate before calling

null

Type guard

function isCloudflareSearchResult(d: unknown): d is { success: true; result: unknown[] } {
  return !!(d as any)?.success && Array.isArray((d as any).result)
}

Try / catch

try { models = await adapter.getModelsAsync() }
catch (e) {
  if (e instanceof APIError && e.message.includes('unexpected response format')) models = FALLBACK_CF_MODELS
  else throw e
}

Prevention

When it happens

Trigger: Cloudflare changes/versions the search API response schema, an intermediate proxy rewrites the response, or a paginated/different endpoint is accidentally targeted via a custom base URL.

Common situations: Custom resolveCloudflareApiBaseURL overrides pointing at the wrong path, gateway mangling responses, upstream API evolution.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/b662d3526e44b724. Report an issue: GitHub.