googleapis/mcp-toolbox · critical

tool type %q already registered

Error message

tool type %q already registered

What it means

This panic is thrown by init() in internal/tools/dataform/dataformcompilelocal because tools.Register for resourceType "dataform-compile-local" found the key already present in the tool registry and returned false. The library fails fast at startup rather than allowing one tool config factory to overwrite another. The remedy is a single, unique registration for this tool type per process.

Source

Thrown at internal/tools/dataform/dataformcompilelocal/dataformcompilelocal.go:34

import (
	"context"
	"fmt"
	"os/exec"
	"strings"

	"github.com/goccy/go-yaml"
	"github.com/googleapis/mcp-toolbox/internal/sources"
	"github.com/googleapis/mcp-toolbox/internal/tools"
	"github.com/googleapis/mcp-toolbox/internal/util"
	"github.com/googleapis/mcp-toolbox/internal/util/parameters"
)

const resourceType string = "dataform-compile-local"

func init() {
	if !tools.Register(resourceType, newConfig) {
		panic(fmt.Sprintf("tool type %q already registered", resourceType))
	}
}

func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
	actual := Config{ConfigBase: tools.ConfigBase{Name: name}}
	if err := decoder.DecodeContext(ctx, &actual); err != nil {
		return nil, err
	}
	return actual, nil
}

type Config struct {
	tools.ConfigBase `yaml:",inline"`
	Type             string                 `yaml:"type" validate:"required"`
	Annotations      *tools.ToolAnnotations `yaml:"annotations,omitempty"`
}

var _ tools.ToolConfig = Config{}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Grep for "dataform-compile-local" and remove or rename the duplicate resourceType.
  2. Keep one source of truth for the tool type key in the dataformcompilelocal package.
  3. Run `go build ./...` and unit tests to confirm only one registration executes.
  4. Avoid calling tools.Register manually in tests for types registered by init().

Example fix

// before
const resourceType string = "dataform-compile-local" // duplicate declaration elsewhere
// after
const resourceType string = "dataform-compile-local" // only in dataformcompilelocal.go; duplicate deleted
Defensive patterns

Strategy: validation

Validate before calling

const want = "dataform-compile-local"
// before adding/renaming the tool, run:
//   git grep -n '"dataform-compile-local"' -- '*.go'
// exactly one const declaration is required.

Try / catch

func mustRegister(key string, fn func(context.Context, string, *yaml.Decoder) (tools.ToolConfig, error)) {
    defer func() {
        if r := recover(); r != nil {
            log.Fatalf("tool %s: %v", key, r)
        }
    }()
    if !tools.Register(key, fn) {
        log.Fatalf("tool %s already registered", key)
    }
}

Prevention

When it happens

Trigger: Another file/package declares the same "dataform-compile-local" const and its init() also registers it; or test/bootstrap code calls tools.Register again for the same key after package init already did.

Common situations: Renaming a tool package but keeping the old resourceType that already exists; merging two branches that both add dataform-compile-local; tests that exercise registration explicitly while init has already run.

Related errors


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