ipfs/kubo · error

%s key is not a map

Error message

%s key is not a map

What it means

CheckKey() walks a dotted config path (e.g. "Addresses.API") through nested maps in the config structure. If an intermediate segment resolves to a value that is not a map (and not nil), the path cannot be descended further and this error names the deepest valid prefix of the path.

Source

Thrown at config/config.go:247

func CheckKey(key string) error {
	conf := Config{}

	// Convert an empty config to a map without JSON.
	cursor := ReflectToMap(&conf)

	// Parse the key and verify it's presence in the map.
	var ok bool
	var mapCursor map[string]any

	parts := strings.Split(key, ".")
	for i, part := range parts {
		mapCursor, ok = cursor.(map[string]any)
		if !ok {
			if cursor == nil {
				return nil
			}
			path := strings.Join(parts[:i], ".")
			return fmt.Errorf("%s key is not a map", path)
		}

		cursor, ok = mapCursor[part]
		if !ok {
			// If the config sections is a map, validate against the default entry.
			if cursor, ok = mapCursor["*"]; ok {
				continue
			}
			path := strings.Join(parts[:i+1], ".")
			return fmt.Errorf("%s not found", path)
		}
	}
	return nil
}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Correct the dotted path so each prefix names a config section (map), not a leaf value
  2. Print/inspect the config (ipfs config) to verify the actual nesting at the reported prefix
  3. Stop the path at the reported prefix and set the leaf value directly instead

Example fix

// before
err := SetConfigKey(cfg, "Addresses.API.extra", val) // Addresses.API is a string
// after
err := SetConfigKey(cfg, "Addresses.API", val)
Defensive patterns

Strategy: validation

Validate before calling

// Verify each dotted prefix names an existing section before descending
func pathIsSection(cfg *config.Config, dotted string) bool {
	cur := any(cfg)
	for _, part := range strings.Split(dotted, ".") {
		m, ok := cur.(map[string]any)
		if !ok {
			return false
		}
		cur, ok = m[part]
		if !ok {
			return false
		}
	}
	_, isMap := cur.(map[string]any)
	return isMap
}

Type guard

func isSection(v any) bool {
	_, ok := v.(map[string]any)
	return ok
}

Try / catch

if err := config.CheckKey(cfg, key); err != nil {
	if strings.Contains(err.Error(), "key is not a map") {
		// path crosses a leaf value: correct the key or write the leaf directly
		return fmt.Errorf("invalid config path %q: %w", key, err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling CheckKey or SetConfigKey with a dotted key where an intermediate segment names a scalar value, e.g. "Addresses.API.Sub" when Addresses.API is a string.

Common situations: Typo in the key path causing traversal into a leaf value; config schema change making a formerly-nested section scalar; automation scripts building paths dynamically from bad input.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/50d6e050e115c0a6. Report an issue: GitHub.