Skip to content

fix(core): decode byte-array encoded API error messages#19855

Open
Rohan-Mohite14 wants to merge 6 commits intogoogle-gemini:mainfrom
Rohan-Mohite14:fix/decode-byte-array-errors
Open

fix(core): decode byte-array encoded API error messages#19855
Rohan-Mohite14 wants to merge 6 commits intogoogle-gemini:mainfrom
Rohan-Mohite14:fix/decode-byte-array-errors

Conversation

@Rohan-Mohite14
Copy link
Copy Markdown

Summary

API error messages from the Gemini API are sometimes displayed as raw ASCII byte codes (e.g., 91,123,10,32,34,101,...) instead of readable text. This PR adds decoding logic to convert these byte-array encoded error messages into readable UTF-8 text before formatting and displaying them in the CLI. This improves usability and ensures error messages are understandable.

Details

The @google/genai SDK occasionally returns HTTP error response bodies as a Uint8Array. When this gets stringified into an Error.message, it produces comma-separated ASCII byte values instead of readable JSON error text.

The parseAndFormatApiError() function in packages/core/src/utils/errorParsing.ts did not previously detect or decode this format.

This PR introduces a helper function tryDecodeByteArray() that:

  • Detects comma-separated numeric byte patterns
  • Converts them into a byte array
  • Decodes them into a UTF-8 string
  • Returns the decoded string for proper formatting and display

This decoding is applied in parseAndFormatApiError() in two scenarios:

  • When handling StructuredError objects (decoding .message)
  • When handling raw string error messages

This ensures all API error messages are properly decoded and formatted before being displayed in the CLI.

Related Issues

Fixes #19851

How to Validate

  1. Run the unit tests:

    npm test -w @google/gemini-cli-core -- src/utils/errorParsing.test.ts
  2. Verify that:

    • The new test case correctly decodes byte-array encoded error messages
    • All existing tests pass successfully
    • No regressions occur
  3. Manual validation:

    • Run the Gemini CLI
    • Trigger a RESOURCE_EXHAUSTED (429) error from the API
    • Verify the error message is displayed as readable text instead of comma-separated byte values

Expected result:

  • Previously unreadable byte-array error messages are now properly decoded and human-readable
  • All tests pass successfully

Pre-Merge Checklist

@Rohan-Mohite14 Rohan-Mohite14 requested a review from a team as a code owner February 21, 2026 20:34
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @Rohan-Mohite14, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where API error messages from the Gemini API were sometimes displayed as unreadable byte-array encoded strings. By adding decoding logic, the change ensures that all error messages are converted into human-readable UTF-8 text, significantly enhancing the clarity and understandability of error feedback within the CLI.

Highlights

  • Decode API Error Messages: Implemented logic to convert byte-array encoded API error messages, which previously appeared as raw ASCII byte codes, into readable UTF-8 text for improved usability.
  • New Helper Function tryDecodeByteArray: Introduced a new utility function, tryDecodeByteArray, which detects comma-separated numeric byte patterns, converts them into a byte array, and decodes them into a UTF-8 string.
  • Integration into Error Parsing: Integrated the byte-array decoding logic into the parseAndFormatApiError() function to ensure that both StructuredError objects and raw string error messages are properly decoded before display.
Changelog
  • packages/core/src/utils/errorParsing.test.ts
    • Added a new test case to verify the correct decoding and formatting of byte-array encoded error messages.
  • packages/core/src/utils/errorParsing.ts
    • Introduced tryDecodeByteArray function to detect and decode comma-separated numeric byte patterns into UTF-8 strings.
    • Modified parseAndFormatApiError to apply tryDecodeByteArray when processing StructuredError messages.
    • Modified parseAndFormatApiError to apply tryDecodeByteArray when processing raw string error messages.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces logic to decode byte-array encoded error messages from the Gemini API, which significantly improves the readability of errors in the CLI. No specific security vulnerabilities were identified in this change. General feedback focuses on ensuring the decoding process is robust against non-ASCII characters and large inputs by using TextDecoder instead of String.fromCharCode, and adjusting the new code to follow the established coding style of using braces for all conditional blocks.

@gemini-cli gemini-cli bot added the area/core Issues related to User Interface, OS Support, Core Functionality label Feb 21, 2026
Rohan-Mohite14 and others added 5 commits February 22, 2026 11:41
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@gemini-cli gemini-cli bot added priority/p1 Important and should be addressed in the near term. help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! labels Feb 26, 2026
@@ -40,6 +52,16 @@ export function parseAndFormatApiError(
fallbackModel?: string,
): string {
if (isStructuredError(error)) {
const decoded = tryDecodeByteArray(error.message);
if (decoded) {
return parseAndFormatApiError(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed an edge case here.

When the code successfully decodes error.message and recursively calls
parseAndFormatApiError(decoded, ...), it passes only the new string and
leaves behind the original outer object, dropping error.status.

Timeline of what happens if the API returns a 429 Error:

  1. Input at line 47: { message: "78,111...", status: 429 }
  2. Line 55: tryDecodeByteArray decodes the message into the string
    "No capacity available".
  3. Line 57: The recursive call triggers, passing only the new string:
    parseAndFormatApiError("No capacity available", ...)
  4. The function restarts at line 47. Because the input is now a plain string
    instead of an object, status no longer exists.
  5. Line 66 (if (error.status === 429)) is never reached.

Actual Output: [API Error: No capacity available]

Expected Output:
[API Error: No capacity available]
Please wait and try again later. To increase your limits...

We should clone the error object here so we can preserve the original HTTP
status before recursing:

    if (decoded) {
      return parseAndFormatApiError(
        { ...error, message: decoded },
        authType,
        userTier,
        currentModel,
        fallbackModel,
      );

@Jatin24062005
Copy link
Copy Markdown
Contributor

adding this decoding logic — it makes the CLI error messages much more readable when the API returns byte-array formatted messages.

While reviewing the call chain, I noticed that the CLI itself doesn’t directly perform the HTTP request. The request flow appears to be:

GeminiClient.generateContent()
  → ContentGenerator.generateContent()
  → LoggingContentGenerator
  → @google/genai SDK
  → HTTP request to Gemini API

This suggests the byte-array formatted error may originate upstream in the @google/genai SDK. It’s possible the SDK is converting a Uint8Array (or ArrayBuffer) to a string without decoding it as UTF-8, which would produce the numeric byte sequence we’re seeing.

The current workaround here works well for the CLI, but it might also be worth checking whether the SDK is returning the error body via something like response.arrayBuffer() rather than response.text(). If that’s the case, decoding earlier in the SDK could eliminate the need for this workaround downstream.

@Jatin24062005
Copy link
Copy Markdown
Contributor

Jatin24062005 commented Mar 13, 2026

@Rohan-Mohite14 The existing tryDecodeByteArray logic only detects comma-separated numbers
without brackets, causing the error to be displayed as raw byte values.so my suggestion do something like this

function tryDecodeByteArray(s: string): string | null {
  const cleaned = s.replace(/[\[\]\s]/g, '');

  if (!/^\d+(,\d+)+$/.test(cleaned)) {
    return null;
  }

  try {
    const bytes = new Uint8Array(cleaned.split(',').map(Number));
    return new TextDecoder().decode(bytes);
  } catch {
    return null;
  }
}

This change strips brackets and whitespace before decoding so both formats
are supported:

91,123,10
[91,123,10]
[91, 123, 10]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p1 Important and should be addressed in the near term.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API error messages displayed as raw byte codes instead of decoded text when model capacity is exhausted

3 participants