AlexxIT/go2rtc · error
failed to decode hex
Error message
failed to decode hex: %w
What it means
WakeUp builds a binary payload by decoding the hex string two characters at a time with hex.DecodeString; this error wraps any hex decoding failure. It means the hex string passed to WakeUp is malformed — odd length or containing non-hex characters. The message is never published in this case.
Solutions
- Validate the hex string length is even before calling WakeUp
- Validate all characters are valid hex (regexp ^[0-9a-fA-F]+$)
- Check where the hex string comes from (config/env/DB) for truncation or encoding mistakes
- If the source is base64, decode with base64.StdEncoding instead of hex
Example fix
// before
err := client.WakeUp(devKey)
// after
var re = regexp.MustCompile(`^[0-9a-fA-F]+$`)
if len(devKey)%2 != 0 || !re.MatchString(devKey) {
return fmt.Errorf("invalid hex key: %q", devKey)
}
err := client.WakeUp(devKey) Defensive patterns
Strategy: validation
Validate before calling
var hexRe = regexp.MustCompile(`^[0-9a-fA-F]+$`)
func validHex(s string) bool { return len(s)%2 == 0 && hexRe.MatchString(s) } Type guard
func isHexString(s string) bool {
if len(s) == 0 || len(s)%2 != 0 { return false }
_, err := hex.DecodeString(s)
return err == nil
} Try / catch
if !isHexString(key) { return fmt.Errorf("not a valid hex key: %q", key) }
if err := client.WakeUp(key); err != nil {
var hexErr *hex.InvalidByteError
if errors.As(err, &hexErr) { /* malformed input, do not retry */ }
} Prevention
- Validate hex keys at config-load time, not at call time
- Store keys with a fixed-length schema check
- Never pass base64-encoded keys where hex is expected
When it happens
Trigger: Calling WakeUp with a deviceId-adjacent hex string argument that has an odd number of characters or contains characters outside [0-9a-fA-F]; hex.DecodeString fails on one of the 2-char slices.
Common situations: Happens when a device key or payload was copied with extra whitespace/quotes, when a base64 string is mistakenly passed where hex is expected, or when a truncated key (odd length) is loaded from config.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- loginResp.ErrorMsg
- tuya:
- webRTCConfigResponse.Msg
- openIoTHubConfigResponse.Msg
- failed to publish wake-up message
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/bdd03cd6a5960c60.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/tuya/mqtt.go:183
c.closed = true
}
// WakeUp sends a wake-up signal to battery-powered cameras (LowPower mode).
// The camera wakes up and starts responding immediately - we don't wait for dps[149].
// Note: LowPower cameras sleep after ~3 minutes of inactivity.
func (c *TuyaMqttClient) WakeUp(localKey string) error {
// Calculate CRC32 of localKey as wake-up payload
crc := crc32.ChecksumIEEE([]byte(localKey))
// Convert to hex string
hexStr := fmt.Sprintf("%08x", crc)
// Convert hex string to byte array (2 chars at a time)
payload := make([]byte, len(hexStr)/2)
for i := 0; i < len(hexStr); i += 2 {
b, err := hex.DecodeString(hexStr[i : i+2])
if err != nil {
return fmt.Errorf("failed to decode hex: %w", err)
}
payload[i/2] = b[0]
}
// Publish to wake-up topic: m/w/{deviceId}
wakeUpTopic := fmt.Sprintf("m/w/%s", c.deviceId)
token := c.client.Publish(wakeUpTopic, 1, false, payload)
if token.Wait() && token.Error() != nil {
return fmt.Errorf("failed to publish wake-up message: %w", token.Error())
}
// Subscribe to lowPower topic to receive dps[149] status updates
// (we don't wait for this signal - camera responds immediately)
lowPowerTopic := fmt.Sprintf("smart/decrypt/in/%s", c.deviceId)
if token := c.client.Subscribe(lowPowerTopic, 1, c.onLowPowerMessage); token.Wait() && token.Error() != nil {
return fmt.Errorf("failed to subscribe to lowPower topic: %w", token.Error())
}
View on GitHub (pinned to c245815e75)