Skip to content

Commit 7480766

Browse files
authored
Merge pull request #75 from agent-ecosystem/improve-base-url-error-handling
Improve OpenAI base url error handling
2 parents 26967f0 + c1bf552 commit 7480766

5 files changed

Lines changed: 58 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.5.6]
9+
10+
### Fixed
11+
12+
- Improve error message when the OpenAI API returns an `incorrect_hostname`
13+
error due to regional endpoint requirements ([#70]). The error now tells
14+
the user to set `OPENAI_BASE_URL` or `--base-url` with the correct
15+
regional host (e.g. `https://us.api.openai.com/v1`).
16+
817
## [1.5.5]
918

1019
### Fixed
@@ -202,6 +211,7 @@ First stable release. Includes the complete CLI and importable library packages.
202211
- `types` — shared data types (`Report`, `Result`, `Level`, etc.)
203212
- `judge.LLMClient` interface for custom LLM providers
204213

214+
[1.5.6]: https://github.com/agent-ecosystem/skill-validator/compare/v1.5.5...v1.5.6
205215
[1.5.5]: https://github.com/agent-ecosystem/skill-validator/compare/v1.5.4...v1.5.5
206216
[1.5.4]: https://github.com/agent-ecosystem/skill-validator/compare/v1.5.3...v1.5.4
207217
[1.5.3]: https://github.com/agent-ecosystem/skill-validator/compare/v1.5.2...v1.5.3

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,12 @@ skill-validator score evaluate --provider claude-cli <path>
341341
342342
\*\* The `openai` provider also reads these optional environment variables: `OPENAI_BASE_URL` (API base URL, overridden by `--base-url`), `OPENAI_ORG_ID` (sent as `OpenAI-Organization` header), and `OPENAI_PROJECT_ID` (sent as `OpenAI-Project` header). The org/project headers are only sent when targeting an OpenAI endpoint (e.g. `api.openai.com`, `us.api.openai.com`), not when using third-party compatible APIs.
343343
344+
If your OpenAI organization is bound to a regional endpoint (e.g. `us.api.openai.com` or `eu.api.openai.com`), set `OPENAI_BASE_URL` to the full regional URL including the `/v1` path:
345+
346+
```bash
347+
export OPENAI_BASE_URL=https://us.api.openai.com/v1
348+
```
349+
344350
Use `--model` to override the default model and `--base-url` to point at any OpenAI-compatible endpoint (e.g. `http://localhost:11434/v1` for Ollama). If the endpoint requires a specific token limit parameter, use `--max-tokens-style` to override auto-detection:
345351

346352
| Value | Behavior |

cmd/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/agent-ecosystem/skill-validator/types"
1212
)
1313

14-
const version = "v1.5.5"
14+
const version = "v1.5.6"
1515

1616
var (
1717
outputFormat string

judge/client.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,16 @@ func (c *openaiClient) Complete(ctx context.Context, systemPrompt, userContent s
306306
}
307307

308308
if resp.StatusCode != http.StatusOK {
309+
var errResp struct {
310+
Error struct {
311+
Code string `json:"code"`
312+
Message string `json:"message"`
313+
} `json:"error"`
314+
}
315+
if json.Unmarshal(respBody, &errResp) == nil && errResp.Error.Code == "incorrect_hostname" {
316+
return "", fmt.Errorf("your OpenAI organization requires a regional endpoint: %s\nSet OPENAI_BASE_URL or use --base-url to specify the correct host (e.g. https://us.api.openai.com/v1)",
317+
errResp.Error.Message)
318+
}
309319
return "", fmt.Errorf("API returned status %d: %s", resp.StatusCode, string(respBody))
310320
}
311321

judge/client_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,37 @@ func TestOpenAIClient_OrgProjectHeaders(t *testing.T) {
269269
})
270270
}
271271

272+
func TestOpenAIClient_RegionalHostnameError(t *testing.T) {
273+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
274+
w.Header().Set("Content-Type", "application/json")
275+
w.WriteHeader(http.StatusUnauthorized)
276+
_, _ = fmt.Fprint(w, `{"error":{"message":"Attempted to access resource with incorrect regional hostname. Please make your request to us.api.openai.com","type":"invalid_request_error","code":"incorrect_hostname","param":null},"status":401}`)
277+
}))
278+
defer server.Close()
279+
280+
client, err := NewClient(ClientOptions{
281+
Provider: "openai",
282+
APIKey: "test-key",
283+
BaseURL: server.URL,
284+
Model: "gpt-4o",
285+
})
286+
if err != nil {
287+
t.Fatalf("NewClient: %v", err)
288+
}
289+
290+
_, err = client.Complete(t.Context(), "system", "user")
291+
if err == nil {
292+
t.Fatal("expected error, got nil")
293+
}
294+
295+
if !strings.Contains(err.Error(), "regional endpoint") {
296+
t.Errorf("expected error to mention regional endpoint, got: %v", err)
297+
}
298+
if !strings.Contains(err.Error(), "OPENAI_BASE_URL") {
299+
t.Errorf("expected error to mention OPENAI_BASE_URL, got: %v", err)
300+
}
301+
}
302+
272303
// rewriteTransport rewrites requests to a different target URL while
273304
// preserving the original Host header for testing.
274305
type rewriteTransport struct {

0 commit comments

Comments
 (0)