Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

Regression of #371 — `ResponsesModel.toString()` leaks into Azure deployment URL path via `PrepareRequest.modelNameOrNull()`

Abierto
#967 2 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
68/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
azure, java, kotlin
Área
api, backend

Línea de trabajo

Comienza en PrepareRequest.modelNameOrNull() y sigue cómo ResponseCreateParams.model() devuelve y representa ResponsesModel durante la construcción de la URL de Azure. Ejecuta el ejemplo fijado con mvn clean compile exec:java para observar la ruta generada; se considera terminado cuando el segmento de deployment utiliza gpt-5.4 en lugar de la representación wrapper de ResponsesModel.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Regression of #371 — ResponsesModel.toString() leaks into Azure deployment URL path via PrepareRequest.modelNameOrNull()

Description

When using the Responses API (client.responses().create(...)) against an Azure OpenAI / Azure AI Foundry endpoint configured with a deployment-based (legacy-style) base URL, the generated request URL contains the toString() representation of the internal ResponsesModel wrapper instead of the plain model/deployment name.

This is the same symptom originally reported in #371 ("Malformed URL for Response API when using Azure OpenAI"), which was fixed in v0.44.2 via #387. It appears the fix did not account for the ResponsesModel union/sealed type that was introduced later (supporting a plain string, a ChatModel enum, or a "Responses-only" model), so the same failure mode has resurfaced through a different path.

Reproduction
AzureOpenAIClient client = OpenAIOkHttpClient.builder()
    .baseUrl("https://<resource>.example.azure-api.net/foundry/") // deployment-based / legacy Azure URL mode
    .credential(BearerTokenCredential.create(() -> "<token>"))
    .build();

ResponseCreateParams params = ResponseCreateParams.builder()
    .model("gpt-5.4")
    .input("hello")
    .build();

client.responses().create(params);
Expected URL
POST https://<resource>.example.azure-api.net/foundry/openai/deployments/gpt-5.4/responses?api-version=2024-10-21
Actual URL
POST https://<resource>.example.azure-api.net/foundry/openai/deployments/ResponsesModel%7Bstring=gpt-5.4%7D/responses?api-version=2024-10-21

URL-decoded, the deployment path segment is literally ResponsesModel{string=gpt-5.4} instead of gpt-5.4. The backend/gateway correctly rejects this with a 404 since no such deployment exists.

Root cause

com.openai.core.PrepareRequest.modelNameOrNull() uses Kotlin reflection to find a method named model on the request params, invokes it, unwraps the result if it's an Optional, and then unconditionally calls .toString() on whatever remains:

internal fun Params.modelNameOrNull(): String? {
    val modelName =
        try {
            this::class.declaredFunctions.find { it.name == "model" }?.call(this)
        } catch (_: Exception) {
            null
        }

    return when (modelName) {
        is Optional<*> -> modelName.orElse(null)?.toString()
        else -> modelName?.toString()
    }
}

For ResponseCreateParams, .model() returns Optional<ResponsesModel>. ResponsesModel is a union/sealed wrapper (it can hold a plain String, a ChatModel, or a ResponsesOnlyModel), and its toString() is implemented for debugging/logging purposes:

override fun toString(): String =
    if (this.string != null) "ResponsesModel{string=${this.string}}"
    else if (this.chat != null) "ResponsesModel{chat=${this.chat}}"
    else if (this.only != null) "ResponsesModel{only=${this.only}}"
    else "ResponsesModel{_unknown=${this._json}}"

Because modelNameOrNull() calls .toString() instead of resolving the wrapper via its accessors (e.g. checking isString() and calling asString(), or otherwise handling the chat/only variants), the debug-style string leaks directly into the URL path.

This is analogous to the originally-reported #371 symptom and to #492 (a similar "Optional[ ]" leak for the Azure Image Service), suggesting modelNameOrNull()'s generic reflection + toString() approach is fragile whenever a request type's model field is backed by a union/wrapper type rather than a plain String or simple enum.

Sample app

repro.zip

This Java console app reproduces a bug in the OpenAI Java SDK where the ResponsesModel.toString()
representation leaks into Azure deployment URLs instead of using the plain model name.

The app uses a local MockWebServer to capture the actual request URL generated by the SDK
when making a Responses API call against an Azure OpenAI / Azure AI Foundry endpoint configured
with a deployment-based (legacy-style) base URL. It requires no credentials and sends no
actual request to Azure.

This behavior is a regression of openai-java issue #371.

Build and Run

The reproduction is pinned to com.openai:openai-java:4.56.0 in pom.xml.
Pinning the dependency keeps the sample behavior reproducible if a future SDK version changes
the URL handling.

To build and run:

mvn clean compile exec:java

The output shows the SDK-generated request path, making the ResponsesModel leak
visible without manually constructing the URL.

Lenguaje dominante
Kotlin
Estrellas
1.5k
Forks
264
Merge medio
12 h 15 min
PR fusionados (30 d)
116

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de openai/openai-java

Todos los issues de openai/openai-java

Issues similares

Más issues de Kotlin

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.