tailscale/tailscale · error

%s: invalid hex character: %c

Error message

%s: invalid hex character: %c

What it means

parseID reports the first non-hex character (%c, found by trimming valid hex digits from the left) after encoding/hex.Decode fails. Length was correct but the string contains a character outside 0-9a-fA-F — typically a typo, '0x' prefix, or copy/paste artifact.

Source

Thrown at types/logid/id.go:138

}

func (id PublicID) IsZero() bool {
	return id == PublicID{}
}

func (id PublicID) Prefix64() uint64 {
	return binary.BigEndian.Uint64(id[:8])
}

func parseID[Bytes []byte | string](funcName string, out *[32]byte, in Bytes) (err error) {
	if len(in) != 2*len(out) {
		return fmt.Errorf("%s: invalid hex length: %d", funcName, len(in))
	}
	var hexArr [2 * len(out)]byte
	copy(hexArr[:], in)
	if _, err := hex.Decode(out[:], hexArr[:]); err != nil {
		r, _ := utf8.DecodeRune(bytes.TrimLeft([]byte(in), "0123456789abcdefABCDEF"))
		return fmt.Errorf("%s: invalid hex character: %c", funcName, r)
	}
	return nil
}

func add(id [32]byte, i int64) [32]byte {
	var out uint64
	switch {
	case i < 0:
		borrow := ^uint64(i) + 1 // twos-complement inversion
		for i := 0; i < 4 && borrow > 0; i++ {
			out, borrow = bits.Sub64(binary.BigEndian.Uint64(id[8*(3-i):]), borrow, 0)
			binary.BigEndian.PutUint64(id[8*(3-i):], out)
		}
	case i > 0:
		carry := uint64(i)
		for i := 0; i < 4 && carry > 0; i++ {
			out, carry = bits.Add64(binary.BigEndian.Uint64(id[8*(3-i):]), carry, 0)
			binary.BigEndian.PutUint64(id[8*(3-i):], out)

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Correct or regenerate the log ID string so it is pure lowercase/uppercase hex
  2. Strip any '0x' prefix or separators before parsing
  3. Treat the failing character reported in the message as the location of the typo when fixing source data
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at types/logid/id.go:138 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/37df021e9ae5000a. Report an issue: GitHub.