{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "8968a502d25e" }, "source": [ "##### Copyright 2025 Google LLC." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "cellView": "form", "id": "a73f56372655" }, "outputs": [], "source": [ "# @title Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "id": "35219116d3b3" }, "source": [ "# Gemini API: Error handling" ] }, { "cell_type": "markdown", "metadata": { "id": "571fb2e6d4ba" }, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "id": "b58341384860" }, "source": [ "This Colab notebook demonstrates strategies for handling common errors you might encounter when working with the Gemini API:\n", "\n", "* **Transient Errors:** Temporary failures due to network issues, server overload, etc.\n", "* **Rate Limits:** Restrictions on the number of requests you can make within a certain timeframe.\n", "* **Timeouts:** When an API call takes too long to complete.\n", "\n", "You have two main approaches to explore:\n", "\n", "1. **Automatic retries:** A simple way to retry requests when they fail due to transient errors.\n", "2. **Manual backoff and retry:** A more customizable approach that provides finer control over retry behavior.\n", "\n", "\n", "**Gemini Rate Limits**\n", "\n", "The default rate limits for different Gemini models are outlined in the [Gemini API model documentation](https://ai.google.dev/gemini-api/docs/models/gemini#model-variations). If your application requires a higher quota, consider [requesting a rate limit increase](https://ai.google.dev/gemini-api/docs/quota)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "b2bb83e651f4" }, "outputs": [], "source": [ "%pip install -q -U \"google-generativeai>=0.7.2\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "34bf10124280" }, "outputs": [], "source": [ "import google.generativeai as genai" ] }, { "cell_type": "markdown", "metadata": { "id": "cf16b627705c" }, "source": [ "### Setup your API key\n", "\n", "To run the following cells, store your API key in a Colab Secret named `GOOGLE_API_KEY`. If you don't have an API key or need help creating a Colab Secret, see the [Authentication](https://github.com/google-gemini/cookbook/blob/main/quickstarts/Authentication.ipynb) guide." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "34e7b42a93e3" }, "outputs": [], "source": [ "from google.colab import userdata\n", "\n", "GOOGLE_API_KEY = userdata.get(\"GOOGLE_API_KEY\")\n", "genai.configure(api_key=GOOGLE_API_KEY)" ] }, { "cell_type": "markdown", "metadata": { "id": "89d975abf7a2" }, "source": [ "### Automatic retries\n", "\n", "The Gemini API's client library offers built-in retry mechanisms for handling transient errors. You can enable this feature by using the `request_options` argument with API calls like `generate_content`, `generate_answer`, `embed_content`, and `generate_content_async`.\n", "\n", "**Advantages:**\n", "\n", "* **Simplicity:** Requires minimal code changes for significant reliability gains.\n", "* **Robust:** Effectively addresses most transient errors without additional logic.\n", "\n", "**Customize retry behavior:**\n", "\n", "Use these settings in [`retry`](https://googleapis.dev/python/google-api-core/latest/retry.html) to customize retry behavior:\n", "\n", "* `predicate`: (callable) Determines if an exception is retryable. Default: [`if_transient_error`](https://github.com/googleapis/python-api-core/blob/main/google/api_core/retry/retry_base.py#L75C4-L75C13)\n", "* `initial`: (float) Initial delay in seconds before the first retry. Default: `1.0`\n", "* `maximum`: (float) Maximum delay in seconds between retries. Default: `60.0`\n", "* `multiplier`: (float) Factor by which the delay increases after each retry. Default: `2.0`\n", "* `timeout`: (float) Total retry duration in seconds. Default: `120.0`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "09d14986b9cf" }, "outputs": [ { "data": { "text/plain": [ "response:\n", "GenerateContentResponse(\n", " done=True,\n", " iterator=None,\n", " result=protos.GenerateContentResponse({\n", " \"candidates\": [\n", " {\n", " \"content\": {\n", " \"parts\": [\n", " {\n", " \"text\": \"Flora found it nestled between a chipped ceramic gnome and a stack of moth-eaten doilies at Mrs. Higgins' \\\"Everything Must Go\\\" yard sale. It was a simple, canvas backpack, faded green with worn leather straps. Nothing outwardly magical, but a faint shimmer, like heat rising off asphalt, clung to it. Mrs. Higgins, a woman who smelled perpetually of lavender and forgotten secrets, just winked and said, \\\"That one's got stories, dear. Take good care of 'em.\\\"\\n\\nFlora, a daydreamer with a penchant for adventure, paid the dollar without hesitation. She loved stories. She loved adventures even more.\\n\\nThe first hint of magic came the next day. Flora, late for her history class, rummaged through the backpack for her textbook. Instead of a heavy tome, she pulled out a perfectly ripe, crimson apple. She blinked. Maybe she'd packed a snack and forgotten? But then she reached in again, searching for her notebook, and this time, she unearthed a small, intricately carved wooden bird that chirped softly in her hand.\\n\\nThe backpack, it turned out, wasn't just magical; it was a wish granter, a storyteller, a quirky companion.\\n\\nOver the next few weeks, Flora experimented. She wished for a sunny day for her picnic, and the backpack produced a miniature sun, radiating warmth and golden light. She wished for inspiration for her art project, and out came a jar filled with swirling, iridescent paint that seemed to hum with creativity.\\n\\nThe backpack wasn't always literal, though. Wishing for courage to talk to Liam, the boy with the kind eyes and unruly hair in her art class, resulted in a handful of dried dandelion seeds. Confused, she blew them into the wind, watching them dance and float. As she did, Liam walked by and smiled. He started a conversation about the beauty of impermanence, and suddenly, talking to him wasn't so scary after all.\\n\\nThe backpack's stories manifested in even more unusual ways. Wishing for help with her math homework produced a handful of polished pebbles, each with a different symbol etched on it. She spent hours arranging and rearranging them, and eventually, the symbols formed equations that clicked in her mind, unlocking the secrets of algebra.\\n\\nBut the magic wasn't without its caveats. The backpack seemed to understand Flora's deepest desires, but it often presented them in unexpected packages. It was a puzzle, a riddle, a constant invitation to look beyond the surface.\\n\\nOne day, Flora's grandmother fell ill. Desperate, Flora clutched the backpack and wished for her grandmother to get better. This time, the backpack remained stubbornly empty. Frustrated and scared, Flora sobbed, burying her face in the canvas.\\n\\nFinally, a single, wilted rose emerged.\\n\\nTears streamed down Flora's face. She had wanted a miracle cure, a grand gesture. A wilted rose felt like defeat.\\n\\nBut as she held the rose, she noticed a tiny, almost invisible bud at the base of the stem. Hope flickered in her heart. She carefully placed the rose in a vase of water and sat by her grandmother's bedside. She talked to her, read her stories, held her hand.\\n\\nThe rose slowly revived. The bud unfurled, revealing a delicate, peach-colored bloom. And slowly, surely, her grandmother started to recover.\\n\\nThe backpack hadn't provided a cure, but it had reminded Flora of the power of hope, the importance of presence, and the resilience of life, even in the face of decay. It taught her that sometimes, the greatest magic lies not in the grand spectacle, but in the quiet, persistent bloom of love and connection.\\n\\nFlora continued to carry the backpack, not just as a source of wonder, but as a constant reminder that the greatest adventures aren't always about finding magic, but about discovering the magic that already exists within ourselves and the world around us. And sometimes, the best stories are the ones we write ourselves, one wilted rose and blooming bud at a time.\\n\"\n", " }\n", " ],\n", " \"role\": \"model\"\n", " },\n", " \"finish_reason\": \"STOP\",\n", " \"avg_logprobs\": -0.612216614204461\n", " }\n", " ],\n", " \"usage_metadata\": {\n", " \"prompt_token_count\": 8,\n", " \"candidates_token_count\": 842,\n", " \"total_token_count\": 850\n", " },\n", " \"model_version\": \"gemini-2.0-flash\"\n", " }),\n", ")" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from google.api_core import retry\n", "\n", "model = genai.GenerativeModel(\"gemini-2.0-flash\")\n", "prompt = \"Write a story about a magic backpack.\"\n", "\n", "model.generate_content(\n", " prompt, request_options={\"retry\": retry.Retry(predicate=retry.if_transient_error)}\n", ")" ] }, { "cell_type": "markdown", "metadata": { "id": "1abafce2315c" }, "source": [ "### Manually increase timeout when responses take time\n", "\n", "If you encounter `ReadTimeout` or `DeadlineExceeded` errors, meaning an API call exceeds the default timeout (600 seconds), you can manually adjust it by defining `timeout` in the `request_options` argument." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "5bdc7450fcd8" }, "outputs": [ { "data": { "text/plain": [ "response:\n", "GenerateContentResponse(\n", " done=True,\n", " iterator=None,\n", " result=protos.GenerateContentResponse({\n", " \"candidates\": [\n", " {\n", " \"content\": {\n", " \"parts\": [\n", " {\n", " \"text\": \"Maya hated school. Not the learning part, surprisingly, but the social minefield of the cafeteria, the stale air in the hallways, and the constant pressure to fit in. So, when her eccentric Aunt Clara, a woman known for her mismatched socks and pronouncements like \\\"The moon is made of cheese! Don't let anyone tell you otherwise!\\\", gifted her a battered, leather backpack, Maya wasn't exactly thrilled.\\n\\n\\\"It's... vintage,\\\" Aunt Clara had said, her eyes twinkling. \\\"And a little bit... special.\\\"\\n\\nSpecial turned out to be an understatement. On her first day carrying it, Maya reached inside for a pencil and instead pulled out a perfectly ripe mango. Baffled, she rummaged again and found a tiny, intricately carved wooden bird. The next day, it was a feather that shimmered with iridescent colours.\\n\\nThe backpack, she realized, was magic. It provided whatever she needed, or perhaps, whatever she deeply desired, although it did so in a quirky, unpredictable way. During a pop quiz she'd forgotten to study for, she reached in desperation and pulled out not the answers, but a calming chamomile tea bag and a miniature Zen garden, which helped her focus and at least remember the basic concepts. When she felt lonely, she found a small, handwritten note inside that read, \\\"You are loved.\\\"\\n\\nAt first, Maya reveled in the backpack's gifts. Need a cool outfit for the school dance? The backpack produced a stunning vintage dress, perfectly tailored. Hungry after basketball practice? A steaming bowl of her grandmother's famous chicken soup materialized. She became the most popular girl in school, not because she tried to be, but because the backpack seemed to instinctively know what would make people happy.\\n\\nShe shared the backpack's gifts, pulling out spare scarves for shivering classmates, lending pencils that wrote in shimmering gold ink, and even conjuring up a first-aid kit when a friend scraped her knee. But as her popularity grew, so did the requests. And Maya felt a growing unease. The backpack wasn't a vending machine for happiness. It was something more personal, something that understood her needs.\\n\\nOne day, a group of popular girls cornered her, their eyes glittering with greed. \\\"We need new phones,\\\" Chloe, the queen bee, demanded. \\\"The latest ones. Can your backpack do that?\\\"\\n\\nMaya hesitated. Could it? She wasn't sure she wanted it to. The backpack was starting to feel less like a gift and more like a burden.\\n\\nThat night, she sat alone in her room, the backpack on the floor beside her. She reached inside, not searching for anything specific, just wanting to feel connected to its magic. She pulled out a single, smooth stone, painted with a simple swirl of white.\\n\\nAs she held it, she understood. The backpack wasn't about material things. It was about connection, about empathy, about seeing the world with a little more wonder. The swirling pattern on the stone reminded her of the swirling emotions inside her, the desire to please, the fear of losing her friends, the longing for something more authentic.\\n\\nThe next day, Chloe and her crew approached her again. \\\"So, the phones?\\\" Chloe asked, her voice sharp.\\n\\nMaya took a deep breath. \\\"No,\\\" she said, her voice surprisingly steady. \\\"The backpack doesn't do phones. But it does offer friendship, if you're interested.\\\"\\n\\nThe girls scoffed and walked away. Maya felt a pang of sadness, but also a sense of relief. She had made a choice, a choice to be true to herself, to what she believed in.\\n\\nLater that day, a quiet girl named Sarah, who usually sat alone at lunch, approached Maya. \\\"I saw what happened with Chloe,\\\" she said shyly. \\\"That was brave.\\\"\\n\\nMaya smiled. \\\"Thanks. Want to see something cool?\\\" She reached into the backpack and pulled out two miniature telescopes. \\\"Aunt Clara says the constellations are whispering secrets. Want to listen?\\\"\\n\\nSarah's eyes lit up. As they sat together, looking up at the stars, Maya realized that true magic wasn't about instant gratification or fleeting popularity. It was about finding connection, about sharing wonder, and about being true to yourself. The backpack hadn't made her happy, it had shown her where to find it. And that, she knew, was a magic that would last a lifetime.\\n\"\n", " }\n", " ],\n", " \"role\": \"model\"\n", " },\n", " \"finish_reason\": \"STOP\",\n", " \"avg_logprobs\": -0.5837301393328346\n", " }\n", " ],\n", " \"usage_metadata\": {\n", " \"prompt_token_count\": 8,\n", " \"candidates_token_count\": 919,\n", " \"total_token_count\": 927\n", " },\n", " \"model_version\": \"gemini-2.0-flash\"\n", " }),\n", ")" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = genai.GenerativeModel(\"gemini-2.0-flash\")\n", "prompt = \"Write a story about a magic backpack.\"\n", "\n", "model.generate_content(\n", " prompt, request_options={\"timeout\": 900}\n", ") # Increase timeout to 15 minutes" ] }, { "cell_type": "markdown", "metadata": { "id": "c27ccc71fa27" }, "source": [ "**Caution:** While increasing timeouts can be helpful, be mindful of setting them too high, as this can delay error detection and potentially waste resources." ] }, { "cell_type": "markdown", "metadata": { "id": "69dd9fd7f359" }, "source": [ "### Manually implement backoff and retry with error handling\n", "\n", "For finer control over retry behavior and error handling, you can use the [`retry`](https://googleapis.dev/python/google-api-core/latest/retry.html) library (or similar libraries like [`backoff`](https://pypi.org/project/backoff/) and [`tenacity`](https://tenacity.readthedocs.io/en/latest/)). This gives you precise control over retry strategies and allows you to handle specific types of errors differently." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "c134fc5aaecc" }, "outputs": [ { "data": { "text/plain": [ "response:\n", "GenerateContentResponse(\n", " done=True,\n", " iterator=None,\n", " result=protos.GenerateContentResponse({\n", " \"candidates\": [\n", " {\n", " \"content\": {\n", " \"parts\": [\n", " {\n", " \"text\": \"Unzip the impossible with the Magic Backpack \\u2013 adventures await!\\n\"\n", " }\n", " ],\n", " \"role\": \"model\"\n", " },\n", " \"finish_reason\": \"STOP\",\n", " \"avg_logprobs\": -0.7733027384831355\n", " }\n", " ],\n", " \"usage_metadata\": {\n", " \"prompt_token_count\": 10,\n", " \"candidates_token_count\": 13,\n", " \"total_token_count\": 23\n", " },\n", " \"model_version\": \"gemini-2.0-flash\"\n", " }),\n", ")" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from google.api_core import retry, exceptions\n", "\n", "model = genai.GenerativeModel(\"gemini-2.0-flash\")\n", "\n", "\n", "@retry.Retry(\n", " predicate=retry.if_transient_error,\n", " initial=2.0,\n", " maximum=64.0,\n", " multiplier=2.0,\n", " timeout=600,\n", ")\n", "def generate_with_retry(model, prompt):\n", " response = model.generate_content(prompt)\n", " return response\n", "\n", "\n", "prompt = \"Write a one-liner advertisement for magic backpack.\"\n", "\n", "generate_with_retry(model=model, prompt=prompt)" ] }, { "cell_type": "markdown", "metadata": { "id": "85fc3d0bae17" }, "source": [ "### Test the error handling with retry mechanism\n", "\n", "To validate that your error handling and retry mechanism work as intended, define a `generate_content` function that deliberately raises a `ServiceUnavailable` error on the first call. This setup will help you ensure that the retry decorator successfully handles the transient error and retries the operation." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "981415e25158" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error: 503 Service Unavailable\n" ] }, { "data": { "application/vnd.google.colaboratory.intrinsic+json": { "type": "string" }, "text/plain": [ "'Carry anything, anywhere, with the backpack that defies reality!\\n'" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from google.api_core import retry, exceptions\n", "\n", "\n", "@retry.Retry(\n", " predicate=retry.if_transient_error,\n", " initial=2.0,\n", " maximum=64.0,\n", " multiplier=2.0,\n", " timeout=600,\n", ")\n", "def generate_content_first_fail(model, prompt):\n", " if not hasattr(generate_content_first_fail, \"call_counter\"):\n", " generate_content_first_fail.call_counter = 0\n", "\n", " generate_content_first_fail.call_counter += 1\n", "\n", " try:\n", " if generate_content_first_fail.call_counter == 1:\n", " raise exceptions.ServiceUnavailable(\"Service Unavailable\")\n", "\n", " response = model.generate_content(prompt)\n", " return response.text\n", " except exceptions.ServiceUnavailable as e:\n", " print(f\"Error: {e}\")\n", " raise\n", "\n", "\n", "model = genai.GenerativeModel(\"gemini-2.0-flash\")\n", "prompt = \"Write a one-liner advertisement for magic backpack.\"\n", "\n", "generate_content_first_fail(model=model, prompt=prompt)" ] } ], "metadata": { "colab": { "name": "Error_handling.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 0 }