googleapis/mcp-toolbox · error

prompt %q declared more than once

Error message

prompt %q declared more than once

What it means

ParseConfig rejects a toolbox YAML file in which two prompt resources share the same name, because prompt configs are stored in a name-keyed map and duplicates are ambiguous. Before inserting a decoded prompt into promptConfigs, UnmarshalPrimitiveConfig checks for an existing key and fails with this message.

Source

Thrown at internal/server/config.go:322

				embeddingModelConfigs = make(EmbeddingModelConfigs)
			}
			if _, exists := embeddingModelConfigs[name]; exists {
				return nil, nil, nil, nil, nil, nil, fmt.Errorf("embeddingModel %q declared more than once", name)
			}
			embeddingModelConfigs[name] = c
		case "prompt":
			c, err := UnmarshalYAMLPromptConfig(ctx, name, resource)
			if err != nil {
				if len(file.Docs) > 1 {
					return nil, nil, nil, nil, nil, nil, fmt.Errorf("document %d: error unmarshaling %s %q: %w", docIndex, kind, name, err)
				}
				return nil, nil, nil, nil, nil, nil, fmt.Errorf("error unmarshaling %s: %w", kind, err)
			}
			if promptConfigs == nil {
				promptConfigs = make(PromptConfigs)
			}
			if _, exists := promptConfigs[name]; exists {
				return nil, nil, nil, nil, nil, nil, fmt.Errorf("prompt %q declared more than once", name)
			}
			promptConfigs[name] = c
		case "group":
			c, err := UnmarshalYAMLGroupConfig(ctx, name, resource)
			if err != nil {
				if len(file.Docs) > 1 {
					return nil, nil, nil, nil, nil, nil, fmt.Errorf("document %d: error unmarshaling %s %q: %w", docIndex, kind, name, err)
				}
				return nil, nil, nil, nil, nil, nil, fmt.Errorf("error unmarshaling %s: %w", kind, err)
			}
			if groupConfigs == nil {
				groupConfigs = make(GroupConfigs)
			}
			if _, exists := groupConfigs[name]; exists {
				if name == "" {
					return nil, nil, nil, nil, nil, nil, fmt.Errorf("more than one default (nameless) group declared; only one is allowed")
				}
				return nil, nil, nil, nil, nil, nil, fmt.Errorf("group %q declared more than once", name)

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Search the YAML for duplicate prompt names and rename one of them
  2. If merging files, deduplicate prompt keys before concatenating
  3. If both prompts are intended to be distinct, give each a unique name

Example fix

# before
prompts:
  greet: {description: "a"}
  greet: {description: "b"}
# after
prompts:
  greet-en: {description: "a"}
  greet-es: {description: "b"}
Defensive patterns

Strategy: validation

Validate before calling

// Detect duplicate prompt keys before parsing
text, _ := os.ReadFile(path)
seen := map[string]bool{}
for _, m := range regexp.MustCompile(`(?m)^\s{2}([\w-]+):`).FindAllStringSubmatch(string(text), -1) {
	name := m[1]
	if seen[name] {
		fmt.Printf("duplicate prompt key: %s\n", name)
	}
	seen[name] = true
}

Try / catch

if _, _, _, _, _, _, err := server.ParseConfig(ctx, cfg); err != nil {
	if strings.Contains(err.Error(), "declared more than once") {
		log.Fatalf("duplicate resource name in config: %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: A single YAML config (or multi-doc file) declares two 'prompt' entries with identical kindKind/name keys; ParseConfig hits the exists check at internal/server/config.go:322.

Common situations: Copy-pasting a prompt block and forgetting to rename it; merging two config files that both define the same prompt; generating YAML from a script that appends duplicate prompts.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/c0f22697a9f7aa9b. Report an issue: GitHub.