openai / openai/openai-java

OpenAI Java lib 4.41.0 throws OpenAIInvalidDataException in OrganizationCostsResult when parsing amount values

Open
#769 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Kotlin
Stars
1.5k
Forks
264
Avg merge
9h 46m
Merged PRs (30d)
96

Description

Environment:

  • Java VM: Java JDK 8, Java JDK 21 (Azul Systems, Inc.)
  • OpenAI Java: 4.41.0, 4.42.0

Description:

Parsing the amount from a OrganizationCostsResult to a value and currency throws an OpenAIInvalidDataException when amount values like 0E-6176 or 0.003627500000000000000000000000000000 are received.

Code snippet:

OrganizationCostsResult costs = result.asOrganizationCosts();

double value = costs.amount()
                    .flatMap(amount -> amount.value())  // <== exception on amount.value()
                    .orElse(0.0);

Exception thrown:

Exception in thread "main" com.openai.errors.OpenAIInvalidDataException: `value` is invalid, received 0E-6176
    at com.openai.core.JsonField.getOptional$openai_java_core(Values.kt:191)
    at com.openai.models.admin.organization.usage.UsageCostsResponse$Data$Result$OrganizationCostsResult$Amount.value(UsageCostsResponse.kt:6680)
    at com.github.jlangch.venice.util.openai.bugs.UsageCostJsonParserBug.lambda$2(UsageCostJsonParserBug.java:72)
    at java.util.Optional.flatMap(Optional.java:241)
    at com.github.jlangch.venice.util.openai.bugs.UsageCostJsonParserBug.lambda$1(UsageCostJsonParserBug.java:72)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at com.github.jlangch.venice.util.openai.bugs.UsageCostJsonParserBug.lambda$0(UsageCostJsonParserBug.java:59)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at com.github.jlangch.venice.util.openai.bugs.UsageCostJsonParserBug.main(UsageCostJsonParserBug.java:55)

Some additional OpenAIInvalidDataException messages with other values that failed parsing:

`value` is invalid, received 0E-6176
`value` is invalid, received 0.003627500000000000000000000000000000
`value` is invalid, received 0.007605000000000000000000000000000000

Example code demonstrating the parser exception:

package com.github.jlangch.venice.util.openai.bugs;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.admin.organization.usage.UsageCostsParams;
import com.openai.models.admin.organization.usage.UsageCostsResponse;
import com.openai.models.admin.organization.usage.UsageCostsResponse.Data.Result.OrganizationCostsResult;


/**
 * Demonstrates the openai-java <code>OrganizationCostsResult</code> value parser bug
 *
 * Depends on OpenAI:  com.openai:openai-java:4.41.0
 */
public class UsageCostJsonParserBug {

    private UsageCostJsonParserBug() {}

    public static void main(String[] args) {
        final OpenAIClient client = OpenAIOkHttpClient
                                        .builder()
                                        .adminApiKey(System.getenv("OPENAI_ADMIN_KEY"))
                                        .build();

        final long startTime = LocalDate
                                .now(ZoneOffset.UTC)
                                .minusDays(10)
                                .atStartOfDay(ZoneOffset.UTC)
                                .toEpochSecond();

        final long endTime = Instant.now().getEpochSecond();

        final UsageCostsParams params = UsageCostsParams
                                            .builder()
                                            .startTime(startTime)
                                            .endTime(endTime)
                                            .bucketWidth(UsageCostsParams.BucketWidth._1D)
                                            .addGroupBy(UsageCostsParams.GroupBy.PROJECT_ID)
                                            .addGroupBy(UsageCostsParams.GroupBy.API_KEY_ID)
                                            .addGroupBy(UsageCostsParams.GroupBy.LINE_ITEM)
                                            .limit(180)
                                            .build();

        final UsageCostsResponse response = client
                                                .admin()
                                                .organization()
                                                .usage()
                                                .costs(params);

        response.data().forEach(bucket -> {
            final LocalDateTime bucketStart = toLocalDateTime(bucket.startTime());
            final LocalDateTime bucketEnd = toLocalDateTime(bucket.endTime());

            bucket.results().forEach(result -> {
                if (!result.isOrganizationCosts()) {
                    return;
                }

                final OrganizationCostsResult costs = result.asOrganizationCosts();

                try {
                    final double value;

                    if (true) {
                        // The OpenAI value Json number parser throws an exception
                        value = costs.amount()
                                     .flatMap(amount -> amount.value())  // <== exception
                                     .orElse(0.0);
                    }
                    else {
                        // This custom JsonField number parser works fine
                        value = Double.parseDouble(
                                    costs.amount().isPresent()
                                        ? costs.amount().get()._value().asString().orElse("0.0")
                                        : "0.0");
                    }

                    final String currency = costs.amount()
                                                 .flatMap(amount -> amount.currency())
                                                 .orElse("unknown");

                    final String lineItem = costs.lineItem().orElse("-");

                    System.out.println(String.format(
                            "%s – %s | %.6f %s | %s",
                            bucketStart,
                            bucketEnd,
                            value,
                            currency,
                            lineItem));
                }
                catch(Exception ex) {
                    /*
                       Exception:

                       com.openai.errors.OpenAIInvalidDataException: `value` is invalid, received 0E-6176
                          at com.openai.core.JsonField.getOptional$openai_java_core(Values.kt:191)
                          at com.openai.models.admin.organization.usage.UsageCostsResponse$Data$Result$OrganizationCostsResult$Amount.value(UsageCostsResponse.kt:6680)

                       Some exception messages:

                          `value` is invalid, received 0E-6176
                          `value` is invalid, received 0.003627500000000000000000000000000000
                          `value` is invalid, received 0.007605000000000000000000000000000000


                        Exception in thread "main" com.openai.errors.OpenAIInvalidDataException: `value` is invalid, received 0E-6176
                            at com.openai.core.JsonField.getOptional$openai_java_core(Values.kt:191)
                            at com.openai.models.admin.organization.usage.UsageCostsResponse$Data$Result$OrganizationCostsResult$Amount.value(UsageCostsResponse.kt:6680)
                            at com.github.jlangch.venice.util.openai.bugs.UsageCostJsonParserBug.lambda$2(UsageCostJsonParserBug.java:72)
                            at java.util.Optional.flatMap(Optional.java:241)
                            at com.github.jlangch.venice.util.openai.bugs.UsageCostJsonParserBug.lambda$1(UsageCostJsonParserBug.java:72)
                            at java.util.ArrayList.forEach(ArrayList.java:1259)
                            at com.github.jlangch.venice.util.openai.bugs.UsageCostJsonParserBug.lambda$0(UsageCostJsonParserBug.java:59)
                            at java.util.ArrayList.forEach(ArrayList.java:1259)
                            at com.github.jlangch.venice.util.openai.bugs.UsageCostJsonParserBug.main(UsageCostJsonParserBug.java:55)
                     */
                    System.out.println("Exception: " + ex.getMessage());

                    throw ex;
                }
            });
        });
    }


    private static LocalDateTime toLocalDateTime(final long epochSeconds) {
        return LocalDateTime.ofInstant(
                Instant.ofEpochSecond(epochSeconds),
                ZoneOffset.UTC);
    }

}

If the custom JsonField number parser in the above example is activated the cost items are fine. NoOpenAIInvalidDataExceptions:

2026-06-26T00:00 – 2026-06-27T00:00 | 0.000000 usd | gpt-5.4-2026-03-05, cached input
2026-06-26T00:00 – 2026-06-27T00:00 | 0.003210 usd | gpt-5.4-2026-03-05, input
2026-06-26T00:00 – 2026-06-27T00:00 | 0.008490 usd | gpt-5.4-2026-03-05, output
2026-06-26T00:00 – 2026-06-27T00:00 | 0.000000 usd | gpt-5-search-api-2025-10-14, cached input
2026-06-26T00:00 – 2026-06-27T00:00 | 0.059730 usd | gpt-5-search-api-2025-10-14, input
2026-06-26T00:00 – 2026-06-27T00:00 | 0.010290 usd | gpt-5-search-api-2025-10-14, output
2026-06-26T00:00 – 2026-06-27T00:00 | 0.020000 usd | web search tool calls
2026-06-27T00:00 – 2026-06-28T00:00 | 0.000000 usd | gpt-5.4-2026-03-05, cached input
2026-06-27T00:00 – 2026-06-28T00:00 | 0.002495 usd | gpt-5.4-2026-03-05, input
2026-06-27T00:00 – 2026-06-28T00:00 | 0.003525 usd | gpt-5.4-2026-03-05, output
2026-06-28T00:00 – 2026-06-29T00:00 | 0.000000 usd | gpt-5.4-2026-03-05, cached input
2026-06-28T00:00 – 2026-06-29T00:00 | 0.027858 usd | gpt-5.4-2026-03-05, input
2026-06-28T00:00 – 2026-06-29T00:00 | 0.106335 usd | gpt-5.4-2026-03-05, output
2026-06-28T00:00 – 2026-06-29T00:00 | 0.000000 usd | gpt-5.5-2026-04-23, cached input
2026-06-28T00:00 – 2026-06-29T00:00 | 0.083110 usd | gpt-5.5-2026-04-23, input
2026-06-28T00:00 – 2026-06-29T00:00 | 0.625530 usd | gpt-5.5-2026-04-23, output

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with JsonField in Values.kt and the OrganizationCostsResult.Amount.value() path in UsageCostsResponse.kt, using the supplied Java example and failing values as the reproduction. Check how the numeric values are parsed, then verify that values such as 0E-6176 and the long decimal amounts can be read without OpenAIInvalidDataException.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, kotlin
Domain
api
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.