DEV Community

Cover image for How to Add Gemma 4 Models to OpenClaw (Fix Missing Model Error)
akartit
akartit

Posted on

How to Add Gemma 4 Models to OpenClaw (Fix Missing Model Error)

Google's Gemma 4 family just dropped — and it's a big deal. Open weights, Apache 2.0 license, multimodal, reasoning-capable, and free to use via the Gemini API. But if you're running OpenClaw as your AI assistant gateway, you'll hit a wall: OpenClaw doesn't have Gemma 4 in its built-in model catalog yet.

Here's how I fixed it in under 5 minutes — for both the 31B Dense and the 26B MoE (A4B) variants.

The Problem

After setting google/gemma-4-31b-it as my default model in OpenClaw, running openclaw models list showed:

Model                          Input   Ctx   Auth  Tags
google/gemma-4-31b-it          -       -     -     default,configured,missing
Enter fullscreen mode Exit fullscreen mode

That missing tag means OpenClaw has the model name in config but no metadata — no input types, no context window size, no API protocol. It doesn't know how to talk to it.

Meanwhile, the raw API works fine:

#!/bin/bash
MODEL_ID="gemma-4-31b-it"
curl -X POST \
  -H "Content-Type: application/json" \
  "https://generativelanguage.googleapis.com/v1beta/models/${MODEL_ID}:streamGenerateContent?key=${GEMINI_API_KEY}" \
  -d '{
    "contents": [{
      "role": "user",
      "parts": [{"text": "Hello, what model are you?"}]
    }],
    "generationConfig": {
      "thinkingConfig": { "thinkingLevel": "HIGH" }
    },
    "tools": [{ "googleSearch": {} }]
  }'
Enter fullscreen mode Exit fullscreen mode

Works perfectly. The problem is purely on OpenClaw's side.

The Fix: Register Custom Model Metadata

OpenClaw's config schema supports a top-level models block where you can inject model definitions that the built-in catalog doesn't have. You need to tell OpenClaw the API protocol, capabilities, and context window for each model.

Step 1: Edit your OpenClaw config

Open ~/.openclaw/openclaw.json and add a models block at the top level:

{
  "models": {
    "mode": "merge",
    "providers": {
      "google": {
        "baseUrl": "https://generativelanguage.googleapis.com/v1beta",
        "models": [
          {
            "id": "gemma-4-31b-it",
            "name": "Gemma 4 31B IT",
            "api": "google-generative-ai",
            "reasoning": true,
            "input": ["text", "image"],
            "contextWindow": 262144,
            "maxTokens": 131072
          },
          {
            "id": "gemma-4-26b-a4b-it",
            "name": "Gemma 4 26B A4B IT (MoE)",
            "api": "google-generative-ai",
            "reasoning": true,
            "input": ["text", "image"],
            "contextWindow": 262144,
            "maxTokens": 262144
          }
        ]
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

What each field does

Field Value Why
mode "merge" Adds to the existing catalog instead of replacing it
baseUrl Google's v1beta endpoint Required by schema, even for the built-in Google provider
api "google-generative-ai" Tells OpenClaw to use Google's native API protocol (not OpenAI-compatible)
reasoning true Both models support configurable thinking modes
input ["text", "image"] Multimodal: text + image (variable aspect ratio & resolution)
contextWindow 262144 262K context window (256K usable + overhead)
maxTokens 131072 / 262144 Max output tokens (31B: 131K, 26B MoE: 262K)

Step 2: Set up Google API auth

Make sure you have a Google auth profile in OpenClaw. If you don't:

openclaw models auth login
# Select "google" provider, "api_key" mode
# Paste your Gemini API key
Enter fullscreen mode Exit fullscreen mode

Or set it via environment variable:

export GEMINI_API_KEY="your-key-here"
Enter fullscreen mode Exit fullscreen mode

Step 3: Validate, restart, verify

# Validate config
openclaw config validate

# Restart the gateway
openclaw gateway restart

# Check models
openclaw models list
Enter fullscreen mode Exit fullscreen mode

You should now see:

Model                          Input      Ctx    Auth  Tags
google/gemma-4-31b-it          text+image 256k   yes   default,configured
google/gemma-4-26b-a4b-it      text+image 256k   yes   configured
Enter fullscreen mode Exit fullscreen mode

No more missing tag!

Step 4: Set your default and test

# Set default model
openclaw models set google/gemma-4-31b-it

# Test it
openclaw agent -m "Hello! What model are you?" --local --session-id test
Enter fullscreen mode Exit fullscreen mode

Response:

"I am Gemma 4, a large language model developed by Google DeepMind."

Auto-Patch Script: One Command to Fix Everything

Don't want to edit JSON by hand? Save this script and run it — it patches your OpenClaw config automatically:

#!/bin/bash
# openclaw-gemma4-patch.sh
# Auto-patches OpenClaw config to add Gemma 4 models (31B Dense + 26B MoE)
# Usage: chmod +x openclaw-gemma4-patch.sh && ./openclaw-gemma4-patch.sh

set -euo pipefail

CONFIG="${OPENCLAW_CONFIG_PATH:-$HOME/.openclaw/openclaw.json}"
BACKUP="${CONFIG}.bak.$(date +%s)"

# --- Preflight checks ---
if ! command -v openclaw &>/dev/null; then
  echo "Error: openclaw not found in PATH" >&2
  exit 1
fi

if ! command -v python3 &>/dev/null; then
  echo "Error: python3 required for JSON patching" >&2
  exit 1
fi

if [ ! -f "$CONFIG" ]; then
  echo "Error: OpenClaw config not found at $CONFIG" >&2
  echo "Run 'openclaw configure' first or set OPENCLAW_CONFIG_PATH" >&2
  exit 1
fi

echo "Backing up config to $BACKUP"
cp "$CONFIG" "$BACKUP"

# --- Patch the config ---
python3 << 'PYEOF'
import json, sys, os

config_path = os.environ.get("OPENCLAW_CONFIG_PATH",
    os.path.expanduser("~/.openclaw/openclaw.json"))

with open(config_path, "r") as f:
    config = json.load(f)

gemma4_models = [
    {
        "id": "gemma-4-31b-it",
        "name": "Gemma 4 31B IT",
        "api": "google-generative-ai",
        "reasoning": True,
        "input": ["text", "image"],
        "contextWindow": 262144,
        "maxTokens": 131072
    },
    {
        "id": "gemma-4-26b-a4b-it",
        "name": "Gemma 4 26B A4B IT (MoE)",
        "api": "google-generative-ai",
        "reasoning": True,
        "input": ["text", "image"],
        "contextWindow": 262144,
        "maxTokens": 262144
    }
]

if "models" not in config:
    config["models"] = {"mode": "merge", "providers": {}}
if "providers" not in config["models"]:
    config["models"]["providers"] = {}
if "google" not in config["models"]["providers"]:
    config["models"]["providers"]["google"] = {
        "baseUrl": "https://generativelanguage.googleapis.com/v1beta",
        "models": []
    }

google = config["models"]["providers"]["google"]
if "baseUrl" not in google:
    google["baseUrl"] = "https://generativelanguage.googleapis.com/v1beta"
if "models" not in google:
    google["models"] = []

existing_ids = {m["id"] for m in google["models"]}
added = []
for model in gemma4_models:
    if model["id"] not in existing_ids:
        google["models"].append(model)
        added.append(model["id"])

if "agents" in config and "defaults" in config["agents"]:
    defaults = config["agents"]["defaults"]
    if "models" not in defaults:
        defaults["models"] = {}
    for model in gemma4_models:
        key = f"google/{model['id']}"
        if key not in defaults["models"]:
            defaults["models"][key] = {}

ordered = {"models": config.pop("models")}
ordered.update(config)

with open(config_path, "w") as f:
    json.dump(ordered, f, indent=2)
    f.write("\n")

if added:
    print(f"Added models: {', '.join(added)}")
else:
    print("Models already present, no changes needed")
PYEOF

# --- Validate ---
echo ""
echo "Validating config..."
if ! openclaw config validate; then
  echo "Validation failed! Restoring backup..."
  cp "$BACKUP" "$CONFIG"
  echo "Restored. Please check your config manually."
  exit 1
fi

# --- Restart gateway ---
echo ""
echo "Restarting gateway..."
openclaw gateway restart

# --- Verify ---
echo ""
echo "Verifying models..."
openclaw models list

echo ""
echo "Done! Gemma 4 models are ready."
echo "Set your default with: openclaw models set google/gemma-4-31b-it"
echo "Test with: openclaw agent -m 'Hello!' --local --session-id test-gemma"
Enter fullscreen mode Exit fullscreen mode

Save it and run:

chmod +x openclaw-gemma4-patch.sh
./openclaw-gemma4-patch.sh
Enter fullscreen mode Exit fullscreen mode

The script is idempotent — running it twice won't duplicate models. It backs up your config before patching and auto-rolls back if validation fails.

Testing Both Models

Once patched, verify both variants respond:

# Test the 31B Dense model
openclaw models set google/gemma-4-31b-it
openclaw agent -m "What model are you? One sentence." \
  --local --session-id test-31b --json | python3 -c "
import json,sys
r = json.load(sys.stdin)
print(f'Model: {r[\"meta\"][\"agentMeta\"][\"model\"]}')
print(f'Response: {r[\"payloads\"][0][\"text\"]}')
print(f'Time: {r[\"meta\"][\"durationMs\"]}ms')
"

# Test the 26B MoE model
openclaw models set google/gemma-4-26b-a4b-it
openclaw agent -m "What model are you? One sentence." \
  --local --session-id test-26b --json | python3 -c "
import json,sys
r = json.load(sys.stdin)
print(f'Model: {r[\"meta\"][\"agentMeta\"][\"model\"]}')
print(f'Response: {r[\"payloads\"][0][\"text\"]}')
print(f'Time: {r[\"meta\"][\"durationMs\"]}ms')
"

# Switch back to your preferred default
openclaw models set google/gemma-4-31b-it
Enter fullscreen mode Exit fullscreen mode

Test via Raw curl (No OpenClaw)

Verify your API key works before patching:

#!/bin/bash
# test-gemma4-api.sh — Quick API smoke test for both Gemma 4 models
set -e -E

if [ -z "$GEMINI_API_KEY" ]; then
  echo "Error: Set GEMINI_API_KEY first" >&2
  exit 1
fi

for MODEL in gemma-4-31b-it gemma-4-26b-a4b-it; do
  echo "--- Testing $MODEL ---"
  curl -s -X POST \
    -H "Content-Type: application/json" \
    "https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent?key=${GEMINI_API_KEY}" \
    -d '{
      "contents": [{
        "role": "user",
        "parts": [{"text": "What model are you? Reply in one sentence."}]
      }],
      "generationConfig": {
        "thinkingConfig": { "thinkingLevel": "HIGH" }
      }
    }' | python3 -c "
import json,sys
r = json.load(sys.stdin)
for part in r.get('candidates',[{}])[0].get('content',{}).get('parts',[]):
    if 'text' in part:
        print(part['text'])
        break
" 2>/dev/null || echo "FAILED"
  echo ""
done
Enter fullscreen mode Exit fullscreen mode

How I Diagnosed This

  1. openclaw models list — showed model as missing (no metadata)
  2. openclaw config schema — extracted the full JSON schema to find the exact format for custom model definitions
  3. Found the supported api protocols: google-generative-ai, openai-completions, anthropic-messages, ollama, and others
  4. Added the config block, validated with openclaw config validate
  5. Restarted gateway and confirmed with a test message

About Gemma 4

Gemma 4 is Google's latest open model family with three architectures:

Model Type Parameters Active Params Context Memory (BF16)
Gemma 4 E2B Efficient 2B effective 128K 9.6 GB
Gemma 4 E4B Efficient 4B effective 128K 15 GB
Gemma 4 31B Dense 31B 31B 256K 58.3 GB
Gemma 4 26B A4B MoE 26B 4B 256K 48 GB

Key capabilities:

  • Reasoning with configurable thinking modes (OFF/LOW/MEDIUM/HIGH)
  • Multimodal: text, image (all models), video & audio (E2B/E4B)
  • Function calling for agentic workflows
  • Native system prompt support
  • Apache 2.0 license — fully open for commercial use

Free Tier Rate Limits (Gemini API)

Model RPM (Requests/min) TPM (Tokens/min)
Gemma 4 26B 3 / 15 77 / Unlimited
Gemma 4 31B 3 / 15 15.04K / Unlimited

The 31B gets significantly more token throughput on free tier. Both work for experimentation and personal assistant use cases.

The General Pattern: Adding Any Unsupported Model

This same approach works for any model from any provider that OpenClaw doesn't ship in its catalog:

  1. Verify the API key works outside OpenClaw (use curl)
  2. Find the right api protocol from openclaw config schema — options include:
    • google-generative-ai
    • openai-completions
    • openai-responses
    • anthropic-messages
    • ollama
    • bedrock-converse-stream
    • github-copilot
    • azure-openai-responses
  3. Add the models.providers.<name> block with id, api, contextWindow, maxTokens
  4. Validate and restart: openclaw config validate && openclaw gateway restart

That's it. Sixty seconds from "unknown model" to a working agent.


Links:

Top comments (0)