C.W.K.
Stream
Lesson 04 of 05 · published

Chat & Error Handling

~14 min · chat, history, errors, retry

Level 0Spark
0 XP0/35 lessons0/10 achievements
0/140 XP to next level140 XP to go0% complete

Chat is a thin wrapper over generate_content

client.chats.create() returns a chat session that maintains history. Each send_message appends the user turn, calls generate_content with the full history, and appends the model's reply. You could write the same thing yourself in 20 lines — the wrapper just saves you that 20 lines and the bug where you forget to append the model turn.

Streaming chat exists too

chat.send_message_stream(...) is the streaming variant. Same iterator shape as generate_content_stream.

Inspect history when debugging

chat.get_history() returns the full conversation as list[Content]. Useful when you want to print, persist, or rewind state.

Errors are a three-class hierarchy

  • errors.APIError — base class. Catch this if you don't care which sub-class.
  • errors.ClientError — 4xx (400, 401, 403, 404, 429). Your fault: bad request, bad auth, rate limit.
  • errors.ServerError — 5xx (500, 503). Their fault: retry with backoff.

The HTTP status is on e.code; the human-readable message is on e.message.

Code

Multi-turn chat·python
chat = client.chats.create(
    model='gemini-2.5-flash',
    config=types.GenerateContentConfig(
        system_instruction='You are a precise but warm tutor.',
    ),
)

r1 = chat.send_message('Tell me a fact about octopuses.')
print('AI:', r1.text)

r2 = chat.send_message('Now relate that fact to neural networks.')
print('AI:', r2.text)

# Inspect history
for msg in chat.get_history():
    role = msg.role
    text = msg.parts[0].text if msg.parts and hasattr(msg.parts[0], 'text') else '<non-text>'
    print(f'{role}: {text[:80]}...')
Streaming chat·python
chat = client.chats.create(model='gemini-2.5-flash')

for chunk in chat.send_message_stream('Write me a haiku about debugging.'):
    if chunk.text:
        print(chunk.text, end='', flush=True)
print()
Resilient error handling·python
import time
from google.genai import errors

def robust_generate(client, model, contents, max_retries=4):
    for attempt in range(max_retries):
        try:
            return client.models.generate_content(
                model=model, contents=contents)
        except errors.ClientError as e:
            if e.code == 429:
                # Rate limit — exponential backoff
                sleep = min(2 ** attempt, 30)
                print(f'429 — sleeping {sleep}s')
                time.sleep(sleep)
                continue
            # 400/401/403/404 are not transient — re-raise
            raise
        except errors.ServerError as e:
            # 5xx — retry with backoff
            time.sleep(min(2 ** attempt, 30))
            continue
    raise RuntimeError(f'Gave up after {max_retries} retries')

External links

Exercise

Build a chat-loop CLI: read a line from stdin, send it via chat.send_message_stream, stream the reply to stdout, and persist the full history to chat.jsonl after each turn. Wrap every API call in the robust_generate pattern above so a 429 doesn't kill the session. Confirm the conversation persists across restarts by reloading from JSONL on startup.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.