star7th/showdoc · error · Error

AI 生成失败

Error message

AI 生成失败

What it means

Generic message thrown by the AI-generation modal (handleGenerate) when the POST to {serverHost}/api/ai/create (form-urlencoded body with content + user_token) returns a non-OK status. The real status is discarded, so 'AI 生成失败' ('AI generation failed') covers everything from auth rejection to a PHP 500. Server-side, AiController::create() first calls requireLoginUser(); note that a missing admin open_api_key is NOT this error — that case returns 200 with an SSE-formatted error stream.

Source

Thrown at web_src/src/views/modals/page/AIModal/index.vue:163

    // 获取用户 token
    const userInfo = getUserInfoFromStorage()
    if (userInfo && userInfo.user_token) {
      jsonBody.user_token = userInfo.user_token
    }

    // 使用 fetch 实现流式响应
    const url = getServerHost() + '/api/ai/create'
    const response = await fetch(url, {
      method: 'POST',
      body: new URLSearchParams(jsonBody),
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    })

    if (!response.ok) {
      throw new Error('AI 生成失败')
    }

    const reader = response.body?.getReader()
    const decoder = new TextDecoder('utf-8')
    let result = ''

    if (reader) {
      const readChunk = async () => {
        const { value, done } = await reader.read()

        if (!done) {
          const dataString = decoder.decode(value)
          const lines = dataString.trim().split('data: ')

          for (const line of lines) {
            if (line.trim() !== '') {
              try {
                const data = JSON.parse(line.replace('data: ', ''))

View on GitHub (pinned to 6a3fa91eee)

Solutions

  1. Include the status in the thrown error (`throw new Error(`AI 生成失败 (HTTP ${response.status})`)`) and branch on it: 401/403 -> re-login, 404 -> check server host/route, 5xx -> check server logs.
  2. Verify getUserInfoFromStorage() returned a fresh user_token before fetching; if absent, force login instead of posting without credentials.
  3. Confirm the server actually serves /api/ai/create on the host returned by getServerHost() (curl the endpoint with the same form body).
  4. If 5xx, inspect the PHP server log — the same request also triggers server/app/Common/bootstrap.php, whose DB failure produces 500s for every API call.
  5. For streaming errors that DO arrive with status 200, parse the SSE `data:` line containing error_code/error_message and surface that text instead of this generic throw.

Example fix

// before
if (!response.ok) {
  throw new Error('AI 生成失败')
}

// after
if (!response.ok) {
  const detail = await response.text().catch(() => '')
  throw new Error(`AI 生成失败 (HTTP ${response.status}${response.statusText ? ' ' + response.statusText : ''}) ${detail.slice(0, 120)}`.trim())
}
Defensive patterns

Strategy: try-catch

Validate before calling

const userInfo = getUserInfoFromStorage()
if (!userInfo?.user_token) {
  outputContent.value = ''
  generating.value = false
  // prompt login instead of firing a doomed request
  throw new Error('请先登录后再使用 AI 生成')
}

Type guard

function isAiGenerateFailure(e: unknown): e is Error {
  return e instanceof Error && e.message.startsWith('AI 生成失败')
}

Try / catch

try {
  const response = await fetch(url, { /* ... */ })
  if (!response.ok) {
    if (response.status === 401 || response.status === 403) throw new Error('登录已过期,请重新登录后再试')
    throw new Error(`AI 生成失败 (HTTP ${response.status})`)
  }
  // ...
} catch (e) {
  generating.value = false
  outputContent.value = e instanceof Error ? e.message : 'AI 生成失败'
}

Prevention

When it happens

Trigger: user_token missing (getUserInfoFromStorage() returned nothing) or expired -> requireLoginUser() rejects with 401/403; getServerHost() misconfigured or server rolled back -> 404; PHP fatal/bootstrap RuntimeException (DB unavailable) -> 500; reverse-proxy failure -> 502/504; logged-in user whose session was invalidated server-side but still present in localStorage.

Common situations: User pastes localStorage/cookie data from another environment so user_token does not match the server; server upgraded and the /api/ai route namespace changed; SQLite file unreadable making every request 500; admin assumes this error means the AI key is missing, but that configuration mistake actually arrives as a 200 SSE error message ('管理员没有在管理后台配置AI助手认证KEY...') rendered into the output area instead.

Related errors


AI-assisted analysis of star7th/showdoc@6a3fa91eee (2026-08-21). Data as JSON: /api/errors/eb1fef85318f0580. Report an issue: GitHub.