Repository: ollama/ollama (language: go)

Issue:
server panic when run gemma-3-27b-it-GGUF
### What is the issue?

(gemma) root@node19:/mnt/nvme2n1/gemma# ollama -v
ollama version is 0.6.0
(gemma) root@node19:/mnt/nvme2n1/gemma# ollama list
NAME                                        ID              SIZE     MODIFIED
hf.co/unsloth/gemma-3-27b-it-GGUF:Q4_K_M    3a14687fd09d    16 GB    2 hours ago

test code

```
import requests
import base64
import json

def parse_image_with_gemma(image_path, prompt, ollama_url="http://localhost:8889/v1/chat/completions", model_name="hf.co/unsloth/gemma-3-27b-it-GGUF:Q4_K_M"):
    """
    Sends an image and prompt to the Ollama API for processing.
    """
    try:
        with open(image_path, "rb") as image_file:
            encoded_image = base64.b64encode(image_file.read()).decode("utf-8")

        payload = {
            "model": model_name,
            "messages": [
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": prompt},
                        {
                            "type": "image_url",
                            "image_url": {"url": f"data:image/jpeg;base64,{encoded_image}"},
                        },
                    ],
                }
            ],
        }

        response = requests.post(ollama_url, json=payload, stream=True)
        response.raise_for_status() # Raise an exception for bad status codes.
        for line in response.iter_lines():
            if line:
                body = json.loads(line)
                print(body['response'], end='', flush=True)
                if 'done' in body and body['done']:
                    break
    except requests.exceptions.RequestException as e:
        print(f"Error during request: {e}")
    except FileNotFoundError:
        print(f"Error: Image file not found at {image_path}")
    except json.JSONDecodeError:
        print("Error: invalid json response")

# Example usage
image_path = "/mnt/nvme2n1/gemma/test.jpg"
prompt = "Describe what is in this image."
parse_image_with_gemma(image_path, prompt)
```

### Relevant log output

```shell
[GIN] 2025/03/13 - 15:53:23 | 500 |  216.479399ms |       127.0.0.1 | POST     "/v1/chat/completions"
time=2025-03-13T15:53:24.713+08:00 level=INFO source=server.go:3634 msg="http: panic serving 127.0.0.1:34336: runtime error: integer divide by zero\ngoroutine 1321 [running]:\nnet/http.(*conn).serve.func1()\n\tnet/http/server.go:1947 +0xbe\npanic({0x5635f73af260?, 0x5635f7ca81c0?})\n\truntime/panic.go:787 +0x132\ngithub.com/ollama/ollama/model/models/gemma3.(*VisionModel).Forward(0xc0cf0e2870?, {0x5635f7506c00?, 0xc0cf0e2870?}, {0x5635f750f210?, 0xc0033aa630?})\n\tgithub.com/ollama/ollama/model/models/gemma3/model_vision.go:88 +0x399\ngithub.com/ollama/ollama/model/models/gemma3.(*Model).EncodeMultimodal(0xc000798070, {0x5635f7506c00, 0xc0cf0e2870}, {0xc12338c000, 0x227ec, 0x227ee})\n\tgithub.com/ollama/ollama/model/models/gemma3/model.go:106 +0x18e\ngithub.com/ollama/ollama/runner/ollamarunner.(*Server).inputs(0xc000034d80, {0x5635f7506c00, 0xc0cf0e2870}, {0xc000318320, 0xa0}, {0xc0cf0e2840, 0x1, 0xc0035d5650?})\n\tgithub.com/ollama/ollama/runner/ollamarunner/runner.go:191 +0x3d2\ngithub.com/ollama/ollama/runner/ollamarunner.(*Server).NewSequence(0xc000034d80, {0xc000318320, 0xa0}, {0xc0cf0e2840, 0x1, 0x1}, {0x8000, {0xc01ec6a3a0, 0x2, 0x2}, ...})\n\tgithub.com/ollama/ollama/runner/ollamarunner/runner.go:103 +0xd5\ngithub.com/ollama/ollama/runner/ollamarunner.(*Server).completion(0xc000034d80, {0x5635f74fd4f8, 0xc0cf0f6000}, 0xc003397b80)\n\tgithub.com/ollama/ollama/runner/ollamarunner/runner.go:602 +0x54f\nnet/http.HandlerFunc.ServeHTTP(0xc000762780?, {0x5635f74fd4f8?, 0xc0cf0f6000?}, 0xc0035d5b60?)\n\tnet/http/server.go:2294 +0x29\nnet/http.(*ServeMux).ServeHTTP(0x5635f61ca125?, {0x5635f74fd4f8, 0xc0cf0f6000}, 0xc003397b80)\n\tnet/http/server.go:2822 +0x1c4\nnet/http.serverHandler.ServeHTTP({0x5635f74f9b10?}, {0x5635f74fd4f8?, 0xc0cf0f6000?}, 0x1?)\n\tnet/http/server.go:3301 +0x8e\nnet/http.(*conn).serve(0xc001bfc3f0, {0x5635f74ff5a8, 0xc00078db90})\n\tnet/http/server.go:2102 +0x625\ncreated by net/http.(*Server).Serve in goroutine 1\n\tnet/http/server.go:3454 +0x485"
```

### OS

Linux

### GPU

Nvidia

### CPU

Intel

### Ollama version

0.6.0


Discussion / hints:
The GGUF files provided by Ollama have the image encoder model in them as well with default keys so Ollama can get the weights for image processing but the models on Hugging Face have a separate image encoder/projector so Ollama can't find those keys in the GGUF file and you see the error. 

Fix patch:
diff --git a/model/model.go b/model/model.go
index 89b6c803bf6..fadea3246e8 100644
--- a/model/model.go
+++ b/model/model.go
@@ -22,6 +22,8 @@ import (
 	"github.com/ollama/ollama/model/input"
 )
 
+var ErrNoVisionModel = errors.New("this model is missing data required for image input")
+
 // Model implements a specific model architecture, defining the forward pass and any model-specific configuration
 type Model interface {
 	Forward(ml.Context, input.Options) (ml.Tensor, error)
diff --git a/model/models/gemma3/model.go b/model/models/gemma3/model.go
index b5311f187c1..24193f15f21 100644
--- a/model/models/gemma3/model.go
+++ b/model/models/gemma3/model.go
@@ -84,6 +84,10 @@ func New(c ml.Config) (model.Model, error) {
 }
 
 func (m *Model) EncodeMultimodal(ctx ml.Context, multimodalData []byte) (any, error) {
+	if len(m.VisionModel.Layers) == 0 {
+		return nil, model.ErrNoVisionModel
+	}
+
 	image, _, err := image.Decode(bytes.NewReader(multimodalData))
 	if err != nil {
 		return nil, err
diff --git a/model/models/mllama/model.go b/model/models/mllama/model.go
index 31ba15dfdc2..071d77ac7a6 100644
--- a/model/models/mllama/model.go
+++ b/model/models/mllama/model.go
@@ -63,6 +63,10 @@ func New(c ml.Config) (model.Model, error) {
 }
 
 func (m *Model) EncodeMultimodal(ctx ml.Context, multimodalData []byte) (any, error) {
+	if len(m.VisionModel.Transformer.Layers) == 0 || len(m.GlobalTransformer.Layers) == 0 {
+		return nil, model.ErrNoVisionModel
+	}
+
 	image, _, err := image.Decode(bytes.NewReader(multimodalData))
 	if err != nil {
 		return nil, err


Test patch: