Skip to content

[Go] ai.Prompt may panic with fatal error: concurrent map read and map write when executed concurrently #3636

@EinBexiii

Description

@EinBexiii

Describe the bug

Executing the same ai.Prompt instance from multiple goroutines can cause a panic:

fatal error: concurrent map read and map write

This does not happen deterministically but occurs under concurrent load.
From the stacktrace it happens inside dotprompt while registering helpers / compiling during Prompt.Render / Prompt.Execute.

Error / Stacktrace (excerpt)

fatal error: concurrent map read and map write

goroutine 320 [running]:
internal/runtime/maps.fatal({0x1059feaa2?, 0x105836558?})
        /usr/local/go/src/runtime/panic.go:1058 +0x20
github.com/google/dotprompt/go/dotprompt.(*Dotprompt).DefineHelper(...)
github.com/google/dotprompt/go/dotprompt.(*Dotprompt).RegisterHelpers(...)
github.com/google/dotprompt/go/dotprompt.(*Dotprompt).Compile(...)
github.com/firebase/genkit/go/ai.renderPrompt(...)
github.com/firebase/genkit/go/ai.(*prompt).Render(...)
github.com/firebase/genkit/go/ai.(*prompt).Execute(...)

To Reproduce

Minimal reproducible example:

package main

import (
	"context"
	"log"
	"sync"

	"github.com/firebase/genkit/go/ai"
	"github.com/firebase/genkit/go/genkit"
)

func test() {
	ctx := context.Background()

	g := genkit.Init(ctx,
		genkit.WithDefaultModel("googleai/gemini-2.5-flash"),
		genkit.WithPromptDir("prompts"),
	)

	// prompts/test.prompt exists and is loaded by WithPromptDir
	p := genkit.LookupPrompt(g, "test")
	if p == nil {
		log.Fatal("prompt not found")
	}

	// Run the same Prompt concurrently
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			_, err := p.Execute(ctx, ai.WithInput(map[string]any{"foo": "bar"}))
			if err != nil {
				log.Println("err:", err)
			}
		}()
	}
	wg.Wait()
}

func main() { test() }

Actual result: sometimes succeeds, sometimes panics with fatal error: concurrent map read and map write.

Expected behavior

ai.Prompt should be safe to execute concurrently across goroutines, or the documentation should clearly state concurrency restrictions.

Runtime

  • OS: macOS Tahoe 26.0
  • Go: go version go1.24.3 darwin/arm64
  • Genkit-Go: github.com/firebase/genkit/go v1.0.4

Additional context

N/A

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