Skip to content

[Go] panic: action "/model/googleai/gemini-2.5-flash" is already registered [recovered, repanicked] #3580

@janishorsts

Description

@janishorsts

Describe the bug

When executing the genkit flows in parallel, the registry panics with `panic: action "/model/googleai/gemini-2.5-flash" is already registered [recovered, repanicked].

I assume the model registration is a long-running process by making the HTTP request(s). Effectively, allowing multiple registrations for the same model to start when it is not registered, with the first completed one succeeding and the remaining ones failing.

To Reproduce

package main

import (
	"context"
	"fmt"
	"log/slog"
	"testing"

	"github.com/firebase/genkit/go/ai"
	"github.com/firebase/genkit/go/genkit"
	"github.com/firebase/genkit/go/plugins/googlegenai"
	"golang.org/x/sync/errgroup"
)

type Input struct {
	Message string `json:"message"`
}

type Output struct {
	Message string `json:"message"`
}

func TestActionAlreadyRegistered(t *testing.T) {
	slog.SetLogLoggerLevel(slog.LevelDebug)

	ctx := t.Context()
	g := genkit.Init(ctx,
		genkit.WithPlugins(new(googlegenai.GoogleAI)),
		genkit.WithDefaultModel("googleai/gemini-2.5-flash"),
	)

	prompt := genkit.DefinePrompt(g, "ping-pong", ai.WithSystem("Play ping pong with me!"))

	f := genkit.DefineFlow(g, "ping-pong", func(ctx context.Context, input Input) (Output, error) {
		res, err := prompt.Execute(ctx, ai.WithMessages(ai.NewUserTextMessage(input.Message)))
		if err != nil {
			return Output{}, fmt.Errorf("ping: %w", err)
		}

		return Output{res.Message.Text()}, nil
	})

	eg, egCtx := errgroup.WithContext(ctx)

	
	for range 2 {
		eg.Go(func() error {
			// this triggers the model registration in parallel and panics
			res, err := f.Run(egCtx, Input{"ping"})
			t.Log(res.Message)
			return err
		})
	}

	err := eg.Wait()
	if err != nil {
		t.Fatalf("want no error, got %v", err)
	}
}

Expected behavior

No panic.

Screenshots

Running tool: /opt/homebrew/Cellar/go/1.25.1/libexec/bin/go test -timeout 30s x -v

=== RUN   TestActionAlreadyRegistered
2025/09/15 21:48:26 DEBUG RegisterPlugin name=googleai
2025/09/15 21:48:26 DEBUG RegisterValue name=/format/json
2025/09/15 21:48:26 DEBUG RegisterValue name=/format/jsonl
2025/09/15 21:48:26 DEBUG RegisterValue name=/format/text
2025/09/15 21:48:26 DEBUG RegisterValue name=/format/array
2025/09/15 21:48:26 DEBUG RegisterValue name=/format/enum
2025/09/15 21:48:26 DEBUG RegisterAction key=/util/generate
2025/09/15 21:48:26 DEBUG Default prompt directory not found, skipping loading .prompt files dir=./prompts
2025/09/15 21:48:26 DEBUG RegisterValue name=genkit/defaultModel
2025/09/15 21:48:26 DEBUG RegisterValue name=genkit/promptDir
2025/09/15 21:48:26 DEBUG RegisterAction key=/executable-prompt/ping-pong
2025/09/15 21:48:26 DEBUG RegisterAction key=/flow/ping-pong
2025/09/15 21:48:26 DEBUG Action.Run name=0x104f72020 input="main.Input{Message:\"ping\"}"
2025/09/15 21:48:26 DEBUG span start name=ping-pong
2025/09/15 21:48:26 DEBUG Action.Run name=0x104f72020 input="main.Input{Message:\"ping\"}"
2025/09/15 21:48:26 DEBUG span start name=ping-pong
2025/09/15 21:48:26 DEBUG Action.Run name=0x104d1a210 input="map[string]interface {}(nil)"
2025/09/15 21:48:26 DEBUG span start name=ping-pong
2025/09/15 21:48:26 DEBUG Action.Run name=0x104d1a210 input="map[string]interface {}(nil)"
2025/09/15 21:48:26 DEBUG span start name=ping-pong
2025/09/15 21:48:26 DEBUG span end name=ping-pong
2025/09/15 21:48:26 DEBUG Action.Run name=0x104d1a200 output="api.ActionRunResult[*github.com/firebase/genkit/go/ai.GenerateActionOptions]{Result:(*ai.GenerateActionOptions)(0x1400012a210), TraceId:\"454e3fc57ca067a92bf161b80537af1a\", SpanId:\"10bc24ae81180d7a\"}" err=<nil>
2025/09/15 21:48:26 DEBUG span end name=ping-pong
2025/09/15 21:48:26 DEBUG Action.Run name=0x104d1a200 output="api.ActionRunResult[*github.com/firebase/genkit/go/ai.GenerateActionOptions]{Result:(*ai.GenerateActionOptions)(0x140001dcb00), TraceId:\"2fde2252cce6b18240c3a0c1d791f1f4\", SpanId:\"dbbe961b0ab9993c\"}" err=<nil>
2025/09/15 21:48:26 DEBUG RegisterAction key=/model/googleai/gemini-2.5-flash
2025/09/15 21:48:26 DEBUG span start name=generate
2025/09/15 21:48:26 DEBUG Action.Run name=0x104d184d0 input="&ai.ModelRequest{Config:interface {}(nil), Docs:[]*ai.Document(nil), Messages:[]*ai.Message{(*ai.Message)(0x140001267b0), (*ai.Message)(0x140001264b0)}, Output:(*ai.ModelOutputConfig)(0x140003c9e90), ToolChoice:\"\", Tools:[]*ai.ToolDefinition{}}"
2025/09/15 21:48:26 DEBUG span start name=googleai/gemini-2.5-flash
2025/09/15 21:48:26 DEBUG span end name=ping-pong
2025/09/15 21:48:26 DEBUG Action.Run name=0x104f72010 output="api.ActionRunResult[x.Output]{Result:main.Output{Message:\"\"}, TraceId:\"\", SpanId:\"\"}" err=<nil>
panic: action "/model/googleai/gemini-2.5-flash" is already registered [recovered, repanicked]

goroutine 40 [running]:
go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).End.deferwrap1()
	/Users/foobar/go/pkg/mod/go.opentelemetry.io/otel/sdk@v1.36.0/trace/span.go:467 +0x28
go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).End(0x14000400000, {0x0, 0x0, 0x14000400000?})
	/Users/foobar/go/pkg/mod/go.opentelemetry.io/otel/sdk@v1.36.0/trace/span.go:500 +0x93c
panic({0x10519cf00?, 0x14000780db0?})
	/opt/homebrew/Cellar/go/1.25.1/libexec/src/runtime/panic.go:783 +0x120
github.com/firebase/genkit/go/internal/registry.(*Registry).RegisterAction(0x140002b9480, {0x140001d8280, 0x20}, {0x105346e60, 0x14000780d90})
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/internal/registry/registry.go:95 +0x204
github.com/firebase/genkit/go/core.(*ActionDef[...]).Register(...)
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/action.go:321
github.com/firebase/genkit/go/internal/registry.(*Registry).ResolveAction(0x140002b9480, {0x140005c0020, 0x20})
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/internal/registry/registry.go:181 +0x1e0
github.com/firebase/genkit/go/core.ResolveActionFor[...]({0x10534fd20, 0x140002b9480}, {0x104fc1bfc, 0x5}, {0x104fd6332, 0x140002b9480?})
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/action.go:330 +0x7c
github.com/firebase/genkit/go/ai.LookupModel({0x10534fd20?, 0x140002b9480?}, {0x104fd6332?, 0x0?})
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/ai/generate.go:197 +0x4c
github.com/firebase/genkit/go/ai.GenerateWithRequest({0x1053443f8, 0x140003fc420}, {0x10534fd20, 0x140002b9480}, 0x140001dcb00, {0x0, 0x0, 0x0?}, 0x0)
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/ai/generate.go:217 +0xe0
github.com/firebase/genkit/go/ai.(*prompt).Execute(0x140003cab40, {0x1053443f8, 0x140003fc420}, {0x140004021b0, 0x1, 0x10491176c?})
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/ai/prompt.go:183 +0x348
x.TestActionAlreadyRegistered.func1({0x1053443f8, 0x140003fc420}, {{0x104fc10ee?, 0x14000191f78?}})
	/Users/foobar/projects/playground/genkit-err/x_test.go:35 +0x25c
github.com/firebase/genkit/go/core.DefineFlow[...].func1({{0x104fc10ee, 0x104f71cc0}})
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/flow.go:53 +0x80
github.com/firebase/genkit/go/core.DefineAction[...].func1({{0x104fc10ee?, 0x10519d5c0?}}, 0x140001f7701?)
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/action.go:95 +0x30
github.com/firebase/genkit/go/core.newAction[...].func1({{0x104fc10ee?, 0x30?}}, 0x14000082808?)
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/action.go:158 +0x30
github.com/firebase/genkit/go/core.(*ActionDef[...]).runWithTelemetry.func3({{0x104fc10ee, 0x14000191f68}})
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/action.go:227 +0x134
github.com/firebase/genkit/go/core/tracing.RunInNewSpan[...]({0x105344430, 0x140001fbea0}, 0x140001f7d30, {{0x104fc10ee, 0xa?}}, 0x140001f7df0?)
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/tracing/tracing.go:245 +0xcb0
github.com/firebase/genkit/go/core.(*ActionDef[...]).runWithTelemetry(0x105354180, {0x105344430, 0x140001fbea0}, {{0x104fc10ee, 0x0?}}, 0x0?)
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/action.go:214 +0x2bc
github.com/firebase/genkit/go/core.(*ActionDef[...]).Run(0x0?, {0x105344430?, 0x140001fbea0?}, {{0x104fc10ee?, 0x0?}}, 0x0?)
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/action.go:177 +0x30
github.com/firebase/genkit/go/core.(*Flow[...]).Run(...)
	/Users/foobar/go/pkg/mod/github.com/firebase/genkit/go@v1.0.3/core/flow.go:123
x.TestActionAlreadyRegistered.func2()
	/Users/foobar/projects/playground/genkit-err/x_test.go:47 +0x44
golang.org/x/sync/errgroup.(*Group).Go.func1()
	/Users/foobar/go/pkg/mod/golang.org/x/sync@v0.16.0/errgroup/errgroup.go:93 +0x4c
created by golang.org/x/sync/errgroup.(*Group).Go in goroutine 36
	/Users/foobar/go/pkg/mod/golang.org/x/sync@v0.16.0/errgroup/errgroup.go:78 +0x90
FAIL	x	0.274s

Runtime:

  • OS: MacOS
  • Version: 15.6.1 (24G90)
  • Genkit Go: v1.0.3

Go version

$ go version
go version go1.25.1 darwin/arm64

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinggo

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions