Tencent/WeKnora · error
embed visitor id contains invalid characters
Error message
embed visitor id contains invalid characters
What it means
ValidateEmbedVisitorID rejects visitor ids containing control characters: any rune below 0x20 or the DEL character 0x7f. This prevents header injection and garbled storage of anonymous visitor identifiers.
Source
Thrown at internal/types/principal.go:136
func EmbedVisitorPrincipal(tenantID uint64, channelID, visitorID string) Principal {
return Principal{
Type: PrincipalEmbedVisitor,
ID: fmt.Sprintf("%d:%s:%s", tenantID, strings.TrimSpace(channelID), strings.TrimSpace(visitorID)),
}
}
// ValidateEmbedVisitorID checks the client-supplied anonymous visitor id.
func ValidateEmbedVisitorID(id string) error {
id = strings.TrimSpace(id)
if id == "" {
return fmt.Errorf("empty embed visitor id")
}
if len(id) > 128 {
return fmt.Errorf("embed visitor id too long (max 128)")
}
for _, r := range id {
if r < 0x20 || r == 0x7f {
return fmt.Errorf("embed visitor id contains invalid characters")
}
}
return nil
}
// MCPOAuthPrincipalFromContext resolves the OAuth token principal for ctx.
// Embed chat sessions map to a per-visitor principal when X-Embed-Visitor is
// present; otherwise OAuth falls back to the chat session principal.
func MCPOAuthPrincipalFromContext(ctx context.Context) Principal {
p, ok := PrincipalFromContext(ctx)
if !ok {
return Principal{}
}
p = p.Normalize()
if p.Type != PrincipalEmbedSession {
return p
}
visitorID := EmbedVisitorIDFromContext(ctx)View on GitHub (pinned to 988cbb0330)
Solutions
- Sanitize the id on the client: strip or reject control characters before sending
- Generate ids programmatically (UUID/hex) so control characters cannot appear
- Replace the id with a freshly generated safe value if it came from untrusted input
- Log/reject at the edge if the input looks like an injection attempt
Example fix
// before
visitorID := rawUserInput // may contain \n or \x00
// after
if strings.ContainsFunc(visitorID, func(r rune) bool { return r < 0x20 || r == 0x7f }) {
visitorID = uuid.NewString()
} Defensive patterns
Strategy: validation
Validate before calling
func hasControlChars(s string) bool {
for _, r := range s { if r < 0x20 || r == 0x7f { return true } }
return false
}
if hasControlChars(visitorID) { visitorID = uuid.NewString() } Type guard
func isSafeVisitorID(id string) bool {
if strings.TrimSpace(id) == "" || len(id) > 128 { return false }
for _, r := range id { if r < 0x20 || r == 0x7f { return false } }
return true
} Try / catch
if err := ValidateEmbedVisitorID(id); err != nil {
if strings.Contains(err.Error(), "invalid characters") {
id = sanitizeOrRegenerate(id)
}
} Prevention
- Generate ids programmatically (UUID/hex) so control chars are impossible
- Sanitize any id derived from user or binary input before sending
- Treat validation failure on untrusted input as a potential injection attempt and log it
When it happens
Trigger: Calling ensureEmbedSession with a visitor id containing newlines, tabs, NUL bytes, or other control characters (or DEL), typically from unparsed raw input or binary-derived values.
Common situations: User-supplied ids passed through unvalidated, ids read from binary sources or corrupted storage, copy-paste including invisible control characters, or injection attempts against the embed endpoint.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- invalid file path: %w
- empty embed visitor id
- embed visitor id too long (max 128)
- join request not found
- failed to retrieve: %s
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/bec871dc2eb34a0e.
Report an issue: GitHub.