{"record":{"id":"190f5088239e0462","repo":"iflytek/astron-agent","slug":"status-statustext","errorCode":null,"errorMessage":"上传失败: ${status} ${statusText}","messagePattern":"上传失败: \\$\\{status\\} \\$\\{statusText\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"console/frontend/src/services/chat.ts","lineNumber":207,"sourceCode":"      };\n    }\n\n    // 设置取消令牌\n    if (abortController) {\n      config.signal = abortController.signal;\n    }\n    // 使用axios发送PUT请求，ArrayBuffer作为data参数\n    const axiosResponse = await axios.create().put(url, data, config);\n\n    // 将axios响应转换为Response对象以保持接口一致性\n    return new Response(null, {\n      status: axiosResponse.status,\n      statusText: axiosResponse.statusText,\n    });\n  } catch (error: any) {\n    const status = error.response?.status || 500;\n    const statusText = error.response?.statusText || error.message;\n    throw new Error(`上传失败: ${status} ${statusText}`);\n  }\n};\n\n/**\n * 上传文件绑定对话\n * @param params\n * @param signal 可选的 AbortSignal，用于取消请求\n * @returns\n */\nexport const uploadFileBindChat = (\n  params: {\n    chatId: number;\n    fileSize: number;\n    fileName: string;\n    fileUrl: string;\n    fileBusinessKey: string;\n    paramName?: string;\n  },","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/frontend/src/services/chat.ts#L189-L225","documentation":"uploadFileToS3 wraps its upload request; if the axios PUT/POST to S3 (or the presigned-URL fetch) fails, it rethrows a generic Error '上传失败: <status> <statusText>' with the HTTP status. This is an HTTP-level failure of the upload request, not an application-level error code.","triggerScenarios":"The S3/MinIO presigned URL has expired before upload; CORS blocks the PUT from the browser (error.response undefined → status 500 with axios message); file exceeds bucket size limits or the configured content-type doesn't match the signature; network failure or 403 from wrong credentials.","commonSituations":"Slow uploads of large files exceeding presigned-URL TTL; MinIO/S3 bucket policy or CORS misconfiguration in self-hosted docker deployments; clock skew invalidating SigV4 signatures; uploading disallowed file types.","solutions":["Log the full error (error.response?.data) — S3 error bodies contain the real reason (SignatureDoesNotMatch, AccessDenied, EntityTooLarge).","Fetch the presigned URL immediately before upload and upload within its TTL; regenerate on failure and retry once.","Check S3/MinIO CORS configuration to allow the console origin, PUT method, and the content-type header.","Surface a user-visible toast with the status and a retry button instead of only throwing."],"exampleFix":"// before\ncatch (error: any) {\n  const status = error.response?.status || 500;\n  throw new Error(`上传失败: ${status} ${statusText}`);\n}\n// after\ncatch (error: any) {\n  if (error.code === 'ERR_NETWORK') {\n    throw new Error('上传失败: 网络错误或CORS被拦截');\n  }\n  const s3Reason = error.response?.data ? String(error.response.data).slice(0, 200) : '';\n  const status = error.response?.status || 500;\n  throw new Error(`上传失败: ${status} ${s3Reason || error.message}`);\n}","handlingStrategy":"retry","validationCode":"// pre-flight checks before upload\nif (file.size > MAX_UPLOAD_BYTES) throw new Error('文件过大');\nif (Date.now() > presignExpiresAt) presign = await fetchPresignedUrl(file);","typeGuard":"function isRetryableUploadError(e: any): boolean {\n  const s = e?.response?.status;\n  return !s || s === 408 || s === 429 || s >= 500;\n}","tryCatchPattern":"try {\n  await uploadFileToS3(url, file);\n} catch (e: any) {\n  if (isRetryableUploadError(e)) {\n    await retryUpload(file, 2);\n  } else {\n    message.error(`上传失败: ${e.message}`);\n  }\n}","preventionTips":["Fetch presigned URLs immediately before upload and regenerate expired ones","Configure S3/MinIO CORS for the console origin, PUT, and content-type headers","Enforce client-side file size/type limits matching server policy","Keep server clocks in sync (NTP) to avoid signature mismatches"],"tags":["s3","file-upload","axios","http","minio"],"backgroundTag":"http-error-response","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}