wavetermdev/waveterm · error

invalid key at position %d: %s

Error message

invalid key at position %d: %s

What it means

For non-bracket segments, ParseSimplePath extracts the key up to the next '.' or '[' and validates it against pathPartKeyRe (`^[a-zA-Z0-9:_#-]+`). Keys containing characters outside that set (dots inside keys, spaces, slashes, unicode, empty keys) fail with 'invalid key at position %d'. This keeps path strings unambiguous.

Source

Thrown at pkg/ijson/ijson.go:86

			end := strings.Index(input[i:], "]")
			if end == -1 {
				return nil, fmt.Errorf("unmatched bracket at position %d", i)
			}
			index, err := strconv.Atoi(input[i+1 : i+end])
			if err != nil {
				return nil, fmt.Errorf("invalid index at position %d: %v", i, err)
			}
			path = append(path, index)
			i += end + 1
		} else {
			// Handle the key
			j := i
			for j < len(input) && input[j] != '.' && input[j] != '[' {
				j++
			}
			key := input[i:j]
			if !pathPartKeyRe.MatchString(key) {
				return nil, fmt.Errorf("invalid key at position %d: %s", i, key)
			}
			path = append(path, key)
			i = j
		}
		if i < len(input) && input[i] == '.' {
			i++
		}
	}

	return path, nil
}

type PathError struct {
	Err string
}

func (e PathError) Error() string {
	return "PathError: " + e.Err

View on GitHub (pinned to a4447c1563)

Solutions

  1. Rename the underlying JSON keys to match [a-zA-Z0-9:_#-], or
  2. bypass ParseSimplePath and construct the Path slice directly as []any{"my key", 0} — Path is just an array of strings/ints.
  3. Pre-sanitize input: split on '.' and '[' and reject segments not matching ^[a-zA-Z0-9:_#-]+$ before calling ParseSimplePath.

Example fix

// before
path, err := ijson.ParseSimplePath("user.full name") // invalid key at position 5
// after
path := ijson.Path{"user", "full name"} // build Path directly for exotic keys
data, err := ijson.SetPath(doc, path, value, nil)
Defensive patterns

Strategy: validation

Validate before calling

var pathPartRe = regexp.MustCompile(`^[a-zA-Z0-9:_#-]+$`)
for _, part := range strings.FieldsFunc(userPath, func(r rune) bool { return r == '.' || r == '[' }) {
    part = strings.TrimSuffix(part, "]")
    if !pathPartRe.MatchString(part) { return fmt.Errorf("invalid path key %q", part) }
}

Try / catch

path, err := ijson.ParseSimplePath(input)
if err != nil {
    if strings.Contains(err.Error(), "invalid key") {
        // fall back to constructing the Path slice directly
        return fmt.Errorf("key contains unsupported characters: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling ParseSimplePath with a path containing a key with disallowed characters: "my key", "a/b", an empty segment like "a..b" (produces empty key), or leading non-matching characters (e.g. ".a" at position 0 gives empty key).

Common situations: Map keys in the target JSON containing spaces, slashes, or punctuation; paths built by naive string concatenation producing double dots; localized/unicode key names.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/c4a2997b0ec8d2df. Report an issue: GitHub.