FiloSottile/age · error

invalid plugin name: %q

Error message

invalid plugin name: %q

What it means

NewIdentityWithoutData validates the plugin name by checking that EncodeIdentity(name, nil) produces a non-empty identity encoding. If it returns empty, the name is not a recognized/supported plugin identity name and construction fails, preventing Identity objects for plugins that cannot encode identities.

Source

Thrown at plugin/client.go:193

	ui       *ClientUI
}

var _ age.Identity = &Identity{}

func NewIdentity(s string, ui *ClientUI) (*Identity, error) {
	name, _, err := ParseIdentity(s)
	if err != nil {
		return nil, err
	}
	return &Identity{
		name: name, encoding: s, ui: ui,
	}, nil
}

func NewIdentityWithoutData(name string, ui *ClientUI) (*Identity, error) {
	s := EncodeIdentity(name, nil)
	if s == "" {
		return nil, fmt.Errorf("invalid plugin name: %q", name)
	}
	return &Identity{
		name: strings.ToLower(name), encoding: s, ui: ui,
	}, nil
}

// Name returns the plugin name, which is used in the recipient ("age1name1...")
// and identity ("AGE-PLUGIN-NAME-1...") encodings, as well as in the plugin
// binary name ("age-plugin-name").
func (i *Identity) Name() string {
	return i.name
}

// String returns the identity encoding string ("AGE-PLUGIN-NAME-1...").
func (i *Identity) String() string {
	return i.encoding
}

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Pass the exact supported plugin name and check for typos or stray whitespace.
  2. Confirm the plugin supports identities; recipient-only plugins cannot be used with NewIdentityWithoutData.
  3. Reject empty/blank names at config load time before calling.
  4. If the plugin is legitimate but unsupported, upgrade the age library/plugin to a version that knows its identity encoding.

Example fix

// before
name := os.Getenv("AGE_PLUGIN") // may be ""
identity, err := age.NewIdentityWithoutData(name, ui) // invalid plugin name: ""
// after
name := strings.TrimSpace(os.Getenv("AGE_PLUGIN"))
if name == "" {
    return fmt.Errorf("AGE_PLUGIN must be set to a supported plugin name")
}
identity, err := age.NewIdentityWithoutData(name, ui)
Defensive patterns

Strategy: validation

Validate before calling

// Go: validate the plugin name before constructing the identity
name := strings.TrimSpace(cfg.PluginName)
if name == "" {
    return fmt.Errorf("plugin name must not be empty")
}

Type guard

func validPluginName(name string) bool {
    return name != "" && strings.TrimSpace(name) == name &&
        plugin.EncodeIdentity(name, nil) != "" // maps to a known identity encoding
}

Try / catch

identity, err := plugin.NewIdentityWithoutData(name, ui)
if err != nil {
    return fmt.Errorf("unsupported plugin identity %q: %w", name, err)
}

Prevention

When it happens

Trigger: Calling NewIdentityWithoutData with a name whose prefix has no registered identity encoding: an empty string, a misspelled plugin name, or a plugin that only supports recipients (no identity scheme). Called by encryptNotPass/decryptNotPass and tests.

Common situations: Typo in the plugin name in config or code; using a recipient-only plugin with the identity constructor; a library version that does not know the plugin's identity encoding; empty name from an unset environment variable or config key.

Related errors


AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31). Data as JSON: /api/errors/006f586d77517954. Report an issue: GitHub.