fatedier/frp · error
%s must be valid UTF-8
Error message
%s must be valid UTF-8
What it means
The identifier contains invalid UTF-8 byte sequences (utf8.ValidString fails). frp requires identifiers to be well-formed UTF-8 so they can be safely logged, compared, and serialized in JSON control messages. This check runs after the empty and length checks, before the printable-character check.
Source
Thrown at pkg/config/v1/validation/name.go:36
"fmt"
"unicode"
"unicode/utf8"
)
const (
// MaxRunIDLength is the maximum number of bytes accepted for a control run ID.
MaxRunIDLength = 64
)
func validateIdentifier(value, kind string, maxLength int) error {
if value == "" {
return fmt.Errorf("%s cannot be empty", kind)
}
if len(value) > maxLength {
return fmt.Errorf("%s is too long: length %d exceeds maximum %d", kind, len(value), maxLength)
}
if !utf8.ValidString(value) {
return fmt.Errorf("%s must be valid UTF-8", kind)
}
for _, r := range value {
if !unicode.IsPrint(r) {
return fmt.Errorf("%s contains non-printable character", kind)
}
}
return nil
}
func ValidateRunID(runID string) error {
return validateIdentifier(runID, "run id", MaxRunIDLength)
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Encode binary IDs as hex or base64 (e.g. hex.EncodeToString(digest[:])) before use
- Ensure source strings come from UTF-8 files/inputs
- If a hash is needed, prefer the plain UUID string form
Example fix
// before sum := sha256.Sum256([]byte(name)) runID := string(sum[:]) // raw bytes, invalid UTF-8 // after sum := sha256.Sum256([]byte(name)) runID := hex.EncodeToString(sum[:])
Defensive patterns
Strategy: validation
Validate before calling
func runIDEncodable(s string) bool { return utf8.ValidString(s) } Type guard
func isValidRunID(s string) bool {
return s != "" && len(s) <= validation.MaxRunIDLength && utf8.ValidString(s)
} Prevention
- hex/base64-encode any binary digest before using it as an identifier
- Keep identifiers ASCII-only to sidestep encoding issues entirely
When it happens
Trigger: Passing a run ID built from raw binary (hash digest bytes, random bytes), a C string with embedded NUL decoded as invalid bytes, or text in a legacy 8-bit encoding (Latin-1) to ValidateRunID.
Common situations: Using sha256.Sum256() output directly instead of hex/base64 encoding it; locale-mismatched config files; buffers reused without truncation appending stale bytes.
Related errors
- %s cannot be empty
- %s is too long: length %d exceeds maximum %d
- invalid transport.protocol, optional values are %v
- unexpected message type %s, want %s
- get natHoleRespMsg error: invalid message type
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/3474d7b11613da77.
Report an issue: GitHub.