Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
563d056f
authored
Jul 31, 2025
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: update error handling to support dynamic error types
parent
6d2e92fb
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
117 additions
and
46 deletions
+117
-46
dto/claude.go
+40
-8
dto/openai_response.go
+61
-3
relay/channel/claude/relay-claude.go
+4
-4
relay/channel/gemini/dto.go
+6
-3
relay/channel/openai/relay-openai.go
+2
-2
relay/channel/openai/relay_responses.go
+2
-2
service/convert.go
+0
-22
service/error.go
+1
-1
types/error.go
+1
-1
No files found.
dto/claude.go
View file @
563d056f
...
...
@@ -2,6 +2,7 @@ package dto
import
(
"encoding/json"
"fmt"
"one-api/common"
"one-api/types"
)
...
...
@@ -284,14 +285,9 @@ func (c *ClaudeRequest) ParseSystem() []ClaudeMediaMessage {
return
mediaContent
}
type
ClaudeError
struct
{
Type
string
`json:"type,omitempty"`
Message
string
`json:"message,omitempty"`
}
type
ClaudeErrorWithStatusCode
struct
{
Error
ClaudeError
`json:"error"`
StatusCode
int
`json:"status_code"`
Error
types
.
ClaudeError
`json:"error"`
StatusCode
int
`json:"status_code"`
LocalError
bool
}
...
...
@@ -303,7 +299,7 @@ type ClaudeResponse struct {
Completion
string
`json:"completion,omitempty"`
StopReason
string
`json:"stop_reason,omitempty"`
Model
string
`json:"model,omitempty"`
Error
*
types
.
ClaudeError
`json:"error,omitempty"`
Error
any
`json:"error,omitempty"`
Usage
*
ClaudeUsage
`json:"usage,omitempty"`
Index
*
int
`json:"index,omitempty"`
ContentBlock
*
ClaudeMediaMessage
`json:"content_block,omitempty"`
...
...
@@ -324,6 +320,42 @@ func (c *ClaudeResponse) GetIndex() int {
return
*
c
.
Index
}
// GetClaudeError 从动态错误类型中提取ClaudeError结构
func
(
c
*
ClaudeResponse
)
GetClaudeError
()
*
types
.
ClaudeError
{
if
c
.
Error
==
nil
{
return
nil
}
switch
err
:=
c
.
Error
.
(
type
)
{
case
types
.
ClaudeError
:
return
&
err
case
*
types
.
ClaudeError
:
return
err
case
map
[
string
]
interface
{}
:
// 处理从JSON解析来的map结构
claudeErr
:=
&
types
.
ClaudeError
{}
if
errType
,
ok
:=
err
[
"type"
]
.
(
string
);
ok
{
claudeErr
.
Type
=
errType
}
if
errMsg
,
ok
:=
err
[
"message"
]
.
(
string
);
ok
{
claudeErr
.
Message
=
errMsg
}
return
claudeErr
case
string
:
// 处理简单字符串错误
return
&
types
.
ClaudeError
{
Type
:
"error"
,
Message
:
err
,
}
default
:
// 未知类型,尝试转换为字符串
return
&
types
.
ClaudeError
{
Type
:
"unknown_error"
,
Message
:
fmt
.
Sprintf
(
"%v"
,
err
),
}
}
}
type
ClaudeUsage
struct
{
InputTokens
int
`json:"input_tokens"`
CacheCreationInputTokens
int
`json:"cache_creation_input_tokens"`
...
...
dto/openai_response.go
View file @
563d056f
...
...
@@ -2,12 +2,18 @@ package dto
import
(
"encoding/json"
"fmt"
"one-api/types"
)
type
SimpleResponse
struct
{
Usage
`json:"usage"`
Error
*
OpenAIError
`json:"error"`
Error
any
`json:"error"`
}
// GetOpenAIError 从动态错误类型中提取OpenAIError结构
func
(
s
*
SimpleResponse
)
GetOpenAIError
()
*
types
.
OpenAIError
{
return
GetOpenAIError
(
s
.
Error
)
}
type
TextResponse
struct
{
...
...
@@ -31,10 +37,15 @@ type OpenAITextResponse struct {
Object
string
`json:"object"`
Created
any
`json:"created"`
Choices
[]
OpenAITextResponseChoice
`json:"choices"`
Error
*
types
.
OpenAIError
`json:"error,omitempty"`
Error
any
`json:"error,omitempty"`
Usage
`json:"usage"`
}
// GetOpenAIError 从动态错误类型中提取OpenAIError结构
func
(
o
*
OpenAITextResponse
)
GetOpenAIError
()
*
types
.
OpenAIError
{
return
GetOpenAIError
(
o
.
Error
)
}
type
OpenAIEmbeddingResponseItem
struct
{
Object
string
`json:"object"`
Index
int
`json:"index"`
...
...
@@ -217,7 +228,7 @@ type OpenAIResponsesResponse struct {
Object
string
`json:"object"`
CreatedAt
int
`json:"created_at"`
Status
string
`json:"status"`
Error
*
types
.
OpenAIError
`json:"error,omitempty"`
Error
any
`json:"error,omitempty"`
IncompleteDetails
*
IncompleteDetails
`json:"incomplete_details,omitempty"`
Instructions
string
`json:"instructions"`
MaxOutputTokens
int
`json:"max_output_tokens"`
...
...
@@ -237,6 +248,11 @@ type OpenAIResponsesResponse struct {
Metadata
json
.
RawMessage
`json:"metadata"`
}
// GetOpenAIError 从动态错误类型中提取OpenAIError结构
func
(
o
*
OpenAIResponsesResponse
)
GetOpenAIError
()
*
types
.
OpenAIError
{
return
GetOpenAIError
(
o
.
Error
)
}
type
IncompleteDetails
struct
{
Reasoning
string
`json:"reasoning"`
}
...
...
@@ -276,3 +292,45 @@ type ResponsesStreamResponse struct {
Delta
string
`json:"delta,omitempty"`
Item
*
ResponsesOutput
`json:"item,omitempty"`
}
// GetOpenAIError 从动态错误类型中提取OpenAIError结构
func
GetOpenAIError
(
errorField
any
)
*
types
.
OpenAIError
{
if
errorField
==
nil
{
return
nil
}
switch
err
:=
errorField
.
(
type
)
{
case
types
.
OpenAIError
:
return
&
err
case
*
types
.
OpenAIError
:
return
err
case
map
[
string
]
interface
{}
:
// 处理从JSON解析来的map结构
openaiErr
:=
&
types
.
OpenAIError
{}
if
errType
,
ok
:=
err
[
"type"
]
.
(
string
);
ok
{
openaiErr
.
Type
=
errType
}
if
errMsg
,
ok
:=
err
[
"message"
]
.
(
string
);
ok
{
openaiErr
.
Message
=
errMsg
}
if
errParam
,
ok
:=
err
[
"param"
]
.
(
string
);
ok
{
openaiErr
.
Param
=
errParam
}
if
errCode
,
ok
:=
err
[
"code"
];
ok
{
openaiErr
.
Code
=
errCode
}
return
openaiErr
case
string
:
// 处理简单字符串错误
return
&
types
.
OpenAIError
{
Type
:
"error"
,
Message
:
err
,
}
default
:
// 未知类型,尝试转换为字符串
return
&
types
.
OpenAIError
{
Type
:
"unknown_error"
,
Message
:
fmt
.
Sprintf
(
"%v"
,
err
),
}
}
}
relay/channel/claude/relay-claude.go
View file @
563d056f
...
...
@@ -612,8 +612,8 @@ func HandleStreamResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud
common
.
SysError
(
"error unmarshalling stream response: "
+
err
.
Error
())
return
types
.
NewError
(
err
,
types
.
ErrorCodeBadResponseBody
)
}
if
claude
Response
.
Error
!=
nil
&&
claudeResponse
.
Error
.
Type
!=
""
{
return
types
.
WithClaudeError
(
*
claude
Response
.
Error
,
http
.
StatusInternalServerError
)
if
claude
Error
:=
claudeResponse
.
GetClaudeError
();
claudeError
!=
nil
&&
claude
Error
.
Type
!=
""
{
return
types
.
WithClaudeError
(
*
claudeError
,
http
.
StatusInternalServerError
)
}
if
info
.
RelayFormat
==
relaycommon
.
RelayFormatClaude
{
FormatClaudeResponseInfo
(
requestMode
,
&
claudeResponse
,
nil
,
claudeInfo
)
...
...
@@ -704,8 +704,8 @@ func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeBadResponseBody
)
}
if
claude
Response
.
Error
!=
nil
&&
claudeResponse
.
Error
.
Type
!=
""
{
return
types
.
WithClaudeError
(
*
claude
Response
.
Error
,
http
.
StatusInternalServerError
)
if
claude
Error
:=
claudeResponse
.
GetClaudeError
();
claudeError
!=
nil
&&
claude
Error
.
Type
!=
""
{
return
types
.
WithClaudeError
(
*
claudeError
,
http
.
StatusInternalServerError
)
}
if
requestMode
==
RequestModeCompletion
{
completionTokens
:=
service
.
CountTextToken
(
claudeResponse
.
Completion
,
info
.
OriginModelName
)
...
...
relay/channel/gemini/dto.go
View file @
563d056f
package
gemini
import
"encoding/json"
import
(
"encoding/json"
"one-api/common"
)
type
GeminiChatRequest
struct
{
Contents
[]
GeminiChatContent
`json:"contents"`
...
...
@@ -32,7 +35,7 @@ func (g *GeminiInlineData) UnmarshalJSON(data []byte) error {
MimeTypeSnake
string
`json:"mime_type"`
}
if
err
:=
js
on
.
Unmarshal
(
data
,
&
aux
);
err
!=
nil
{
if
err
:=
comm
on
.
Unmarshal
(
data
,
&
aux
);
err
!=
nil
{
return
err
}
...
...
@@ -93,7 +96,7 @@ func (p *GeminiPart) UnmarshalJSON(data []byte) error {
InlineDataSnake
*
GeminiInlineData
`json:"inline_data,omitempty"`
// snake_case variant
}
if
err
:=
js
on
.
Unmarshal
(
data
,
&
aux
);
err
!=
nil
{
if
err
:=
comm
on
.
Unmarshal
(
data
,
&
aux
);
err
!=
nil
{
return
err
}
...
...
relay/channel/openai/relay-openai.go
View file @
563d056f
...
...
@@ -184,8 +184,8 @@ func OpenaiHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Respo
if
err
!=
nil
{
return
nil
,
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponseBody
,
http
.
StatusInternalServerError
)
}
if
simpleResponse
.
Error
!=
nil
&&
simpleResponse
.
Error
.
Type
!=
""
{
return
nil
,
types
.
WithOpenAIError
(
*
simpleResponse
.
Error
,
resp
.
StatusCode
)
if
oaiError
:=
simpleResponse
.
GetOpenAIError
();
oaiError
!=
nil
&&
oai
Error
.
Type
!=
""
{
return
nil
,
types
.
WithOpenAIError
(
*
oai
Error
,
resp
.
StatusCode
)
}
forceFormat
:=
false
...
...
relay/channel/openai/relay_responses.go
View file @
563d056f
...
...
@@ -28,8 +28,8 @@ func OaiResponsesHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http
if
err
!=
nil
{
return
nil
,
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponseBody
,
http
.
StatusInternalServerError
)
}
if
responsesResponse
.
Error
!=
nil
{
return
nil
,
types
.
WithOpenAIError
(
*
responsesResponse
.
Error
,
resp
.
StatusCode
)
if
oaiError
:=
responsesResponse
.
GetOpenAIError
();
oaiError
!=
nil
&&
oaiError
.
Type
!=
""
{
return
nil
,
types
.
WithOpenAIError
(
*
oai
Error
,
resp
.
StatusCode
)
}
// 写入新的 response body
...
...
service/convert.go
View file @
563d056f
...
...
@@ -188,28 +188,6 @@ func ClaudeToOpenAIRequest(claudeRequest dto.ClaudeRequest, info *relaycommon.Re
return
&
openAIRequest
,
nil
}
func
OpenAIErrorToClaudeError
(
openAIError
*
dto
.
OpenAIErrorWithStatusCode
)
*
dto
.
ClaudeErrorWithStatusCode
{
claudeError
:=
dto
.
ClaudeError
{
Type
:
"new_api_error"
,
Message
:
openAIError
.
Error
.
Message
,
}
return
&
dto
.
ClaudeErrorWithStatusCode
{
Error
:
claudeError
,
StatusCode
:
openAIError
.
StatusCode
,
}
}
func
ClaudeErrorToOpenAIError
(
claudeError
*
dto
.
ClaudeErrorWithStatusCode
)
*
dto
.
OpenAIErrorWithStatusCode
{
openAIError
:=
dto
.
OpenAIError
{
Message
:
claudeError
.
Error
.
Message
,
Type
:
"new_api_error"
,
}
return
&
dto
.
OpenAIErrorWithStatusCode
{
Error
:
openAIError
,
StatusCode
:
claudeError
.
StatusCode
,
}
}
func
generateStopBlock
(
index
int
)
*
dto
.
ClaudeResponse
{
return
&
dto
.
ClaudeResponse
{
Type
:
"content_block_stop"
,
...
...
service/error.go
View file @
563d056f
...
...
@@ -62,7 +62,7 @@ func ClaudeErrorWrapper(err error, code string, statusCode int) *dto.ClaudeError
text
=
"请求上游地址失败"
}
}
claudeError
:=
dto
.
ClaudeError
{
claudeError
:=
types
.
ClaudeError
{
Message
:
text
,
Type
:
"new_api_error"
,
}
...
...
types/error.go
View file @
563d056f
...
...
@@ -16,8 +16,8 @@ type OpenAIError struct {
}
type
ClaudeError
struct
{
Message
string
`json:"message,omitempty"`
Type
string
`json:"type,omitempty"`
Message
string
`json:"message,omitempty"`
}
type
ErrorType
string
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment