linshenkx/prompt-optimizer · error · APIError

Failed to send message: ${error.message}

Error message

Failed to send message: ${error.message}

What it means

Wrapped APIError thrown by sendMessageStructured when any unexpected exception escapes the request pipeline that is not already a RequestConfigError or APIError. The original message is appended ('Failed to send message: <cause>'). The real cause can be adapter construction, network I/O, or response parsing inside adapter.sendMessage.

Source

Thrown at packages/core/src/services/llm/service.ts:108

        throw new RequestConfigError(`Model ${provider} not found`);
      }

      this.validateModelConfig(modelConfig);
      this.validateMessages(messages);

      // 通过 Registry 获取 Adapter
      const adapter = this.registry.getAdapter(modelConfig.providerMeta.id);

      const runtimeConfig = this.prepareRuntimeConfig(modelConfig);

      // 使用 Adapter 发送消息
      return await adapter.sendMessage(messages, runtimeConfig);

    } catch (error: any) {
      if (error instanceof RequestConfigError || error instanceof APIError) {
        throw error;
      }
      throw new APIError(`Failed to send message: ${error.message}`);
    }
  }

  /**
   * 发送消息(传统格式,只返回主要内容)
   */
  async sendMessage(messages: Message[], provider: string): Promise<string> {
    const response = await this.sendMessageStructured(messages, provider);
    
    // 只返回主要内容,不包含推理内容
    // 如果需要推理内容,请使用 sendMessageStructured 方法
    return response.content;
  }

  /**
   * 发送消息(流式,支持结构化和传统格式)
   */
  async sendMessageStream(

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Inspect error.cause / the appended message to identify the underlying exception before assuming an LLM-service bug
  2. If it's a network issue, verify base URL, proxy env vars, and connectivity to the provider endpoint
  3. If a custom adapter, ensure adapter.sendMessage maps its failures to APIError and log the original stack
  4. Retry with backoff for transient network causes; APIError may be retried only if the cause was transient

Example fix

// before
try { await llm.sendMessageStructured(msgs, 'openai'); }
catch (e) { console.log(String(e)); } // 'Failed to send message: fetch failed' — cause hidden

// after
try { await llm.sendMessageStructured(msgs, 'openai'); }
catch (e) {
  console.error(e instanceof APIError ? e.message : e);
  if (e instanceof Error && e.message.includes('Failed to send message')) {
    // inspect e.cause or network state before retrying
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  await llm.sendMessageStructured(msgs, 'openai');
} catch (e) {
  if (e instanceof APIError) { /* inspect message/cause; retry only transient network causes with backoff */ }
  else throw e;
}

Prevention

When it happens

Trigger: Any non-RequestConfigError/non-APIError thrown inside sendMessageStructured: network failures (ECONNREFUSED, DNS), malformed request payloads, SDK exceptions from the provider client, or bugs in a custom adapter's sendMessage implementation.

Common situations: Provider endpoint unreachable or proxy misconfigured; invalid API key causing the underlying SDK to throw its own error type; custom adapters registered in the registry throwing raw Errors; provider response format changes breaking response parsing.

Related errors


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