Skip to content

Added an error message to nudge folks to the new SDK. #461

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# [Deprecated] Google AI JavaScript SDK for the Gemini API

With Gemini 2.0, we took the chance to create a single unified SDK for all developers who want to use Google's GenAI models (Gemini, Veo, Imagen, etc). As part of that process, we took all of the feedback from this SDK and what developers like about other SDKs in the ecosystem to create the [Google Gen AI SDK](https://github.com/googleapis/js-genai).
> **IMPORTANT:** This SDK is intended for use with older Gemini models (e.g., Gemini 1.0 Pro, Gemini 1.5 Pro). For access to the latest models, including Gemini 2.0 and Gemini 2.5 Pro, please use the newer SDK available at [https://github.com/googleapis/js-genai](https://github.com/googleapis/js-genai).
Copy link

Choose a reason for hiding this comment

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

We can use a much stronger message similar to the Python package, see https://github.com/google-gemini/deprecated-generative-ai-python.

For older models, we want to encourage people to use the new SDK. This SDK will be around not to break the existing users. New comers to the old models should also use the new SDK ;)


=======
With Gemini 2.0, we took the chance to create a single unified SDK for all developers who want to use Google's GenAI models (Gemini, Veo, Imagen, etc). As part of that process, we took all of the feedback from this SDK and what developers like about other SDKs in the ecosystem to create the [Google Gen AI SDK](https://github.com/googleapis/js-genai).

The full migration guide from the old SDK to new SDK is available in the [Gemini API docs](https://ai.google.dev/gemini-api/docs/migrate).

Expand Down
94 changes: 62 additions & 32 deletions src/requests/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,28 @@ export async function getHeaders(url: RequestUrl): Promise<Headers> {
return headers;
}

/**
* Generates the request options to be passed to the fetch API.
* @param requestOptions - The user-defined request options.
* @returns The generated request options.
*/
function buildFetchOptions(requestOptions?: SingleRequestOptions): RequestInit {
const fetchOptions = {} as RequestInit;
if (requestOptions?.signal !== undefined || requestOptions?.timeout >= 0) {
const controller = new AbortController();
if (requestOptions?.timeout >= 0) {
setTimeout(() => controller.abort(), requestOptions.timeout);
}
if (requestOptions?.signal) {
requestOptions.signal.addEventListener("abort", () => {
controller.abort();
});
}
fetchOptions.signal = controller.signal;
}
return fetchOptions;
}

export async function constructModelRequest(
model: string,
task: Task,
Expand Down Expand Up @@ -196,46 +218,54 @@ async function handleResponseNotOk(
response: Response,
url: string,
): Promise<void> {
let message = "";
let originalMessage = "";
let errorDetails;
let isUnsupportedModelError = false;
const newSdkUrl = "https://github.com/googleapis/js-genai";
// Patterns for newer models likely requiring the new SDK
const unsupportedModelPatterns = [/gemini-2/, /gemini-pro-2.0/, /gemini-ultra-2.0/, /gemini-flash-2.5/, /gemini-pro-2.5/, /gemini-2.5-pro/, /gemini-2.5-pro-exp/, /gemini-2.0-flash/];

// Extract model name from the URL
let requestedModel = "unknown";
// Match /v.../models/model-name: or /v.../tunedModels/model-name:
const modelNameMatch = url.match(/\/(v\d+(?:beta)?\d*)\/(?:models|tunedModels)\/([^:]+):/);
if (modelNameMatch && modelNameMatch[2]) {
requestedModel = modelNameMatch[2];
}

try {
const json = await response.json();
message = json.error.message;
if (json.error.details) {
message += ` ${JSON.stringify(json.error.details)}`;
errorDetails = json.error.details;
originalMessage = json.error?.message || ""; // Safely access message
errorDetails = json.error?.details; // Safely access details

// Check 1: Explicit model name check
if (unsupportedModelPatterns.some(pattern => pattern.test(requestedModel))) {
// If the requested model *is* one of the new ones, assume this error is due to SDK incompatibility.
isUnsupportedModelError = true;
}

// Append original details to message if they exist and aren't already in the message
if (errorDetails && !originalMessage.includes(JSON.stringify(errorDetails))) {
originalMessage += ` ${JSON.stringify(errorDetails)}`;
}

} catch (e) {
// ignored
// Error parsing JSON is ignored, proceed with original status/text
}

let finalMessage = `Error fetching from ${url.toString()}: [${response.status} ${response.statusText}] ${originalMessage || 'Server responded with an error.'}`; // Provide default if message is empty

if (isUnsupportedModelError) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

this might be a breaking change if user has client side logic to process the error message. Maybe a safer approach is to log a warning message to the console?

// Prepend the specific message for known unsupported models
finalMessage = `It looks like you're trying to use a newer Gemini model (${requestedModel}) with an older SDK. This model requires the latest SDK. Please upgrade to the latest SDK available at ${newSdkUrl}. Original error: ${finalMessage}`;
} else if ((response.status === 400 || response.status === 404) && (originalMessage.includes("Invalid model") || originalMessage.includes("not found") || originalMessage.includes("API key not valid"))) {
// Add a more general hint for other model-related or key errors that might be due to trying new models/regions
finalMessage += `\nHint: If you are trying to use a newer Gemini model (e.g., Gemini 2.0, 2.5 Pro) or a specific region, ensure your API key is valid for that model/region and consider upgrading to the latest SDK: ${newSdkUrl}`;
}

throw new GoogleGenerativeAIFetchError(
`Error fetching from ${url.toString()}: [${response.status} ${
response.statusText
}] ${message}`,
finalMessage,
response.status,
response.statusText,
errorDetails,
);
}

/**
* Generates the request options to be passed to the fetch API.
* @param requestOptions - The user-defined request options.
* @returns The generated request options.
*/
function buildFetchOptions(requestOptions?: SingleRequestOptions): RequestInit {
const fetchOptions = {} as RequestInit;
if (requestOptions?.signal !== undefined || requestOptions?.timeout >= 0) {
const controller = new AbortController();
if (requestOptions?.timeout >= 0) {
setTimeout(() => controller.abort(), requestOptions.timeout);
}
if (requestOptions?.signal) {
requestOptions.signal.addEventListener("abort", () => {
controller.abort();
});
}
fetchOptions.signal = controller.signal;
}
return fetchOptions;
}
Loading