Tencent/WeKnora · error

sandbox binding session must not contain control characters

Error message

sandbox binding session must not contain control characters

What it means

Character-validation guard in SessionSandboxKey.Validate: fires when the SessionID of a tenant-scoped sandbox binding contains ASCII/Unicode control characters. Control characters in a session identifier could break binding serialization or enable injection into stored keys, so the key is rejected as unable to safely identify a tenant session.

Source

Thrown at internal/sandbox/session_binding.go:32

const SessionSandboxBindingVersion = 1

// SessionSandboxKey identifies one tenant-scoped persistent sandbox.
type SessionSandboxKey struct {
	TenantID  uint64
	SessionID string
}

// Validate rejects keys that cannot identify a tenant session.
func (k SessionSandboxKey) Validate() error {
	if k.TenantID == 0 || strings.TrimSpace(k.SessionID) == "" {
		return errors.New("sandbox binding requires tenant and session")
	}
	if strings.ContainsAny(k.SessionID, "{}") {
		return errors.New("sandbox binding session must not contain braces")
	}
	for _, r := range k.SessionID {
		if unicode.IsControl(r) {
			return errors.New("sandbox binding session must not contain control characters")
		}
	}
	return nil
}

// SessionSandboxBinding records the remote sandbox assigned to a session.
type SessionSandboxBinding struct {
	Version    int            `json:"version"`
	Provider   RemoteProvider `json:"provider,omitempty"`
	TenantID   uint64         `json:"tenant_id"`
	SessionID  string         `json:"session_id"`
	SandboxID  string         `json:"sandbox_id"`
	TemplateID string         `json:"template_id"`
	CreatedAt  time.Time      `json:"created_at"`

	// ConfigID is the sandbox config the sandbox was created from. It is what
	// makes "every sandbox of this config" answerable from the binding store:
	// the sandbox itself carries the same value in provider metadata, but a

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Trim and sanitize the session ID (strings.TrimSpace, strip non-printable runes) before building the key.
  2. Validate identifiers at the API boundary with an allowlist (alphanumeric, hyphen, underscore).
  3. Ensure generators/parsers produce printable IDs (bare hex UUIDs).

Example fix

// before
key := sandbox.SessionSandboxKey{TenantID: 7, SessionID: headerValue} // may contain \n
// after
clean := strings.Map(func(r rune) rune { if unicode.IsControl(r) { return -1 }; return r }, strings.TrimSpace(headerValue))
key := sandbox.SessionSandboxKey{TenantID: 7, SessionID: clean}
Defensive patterns

Strategy: validation

Validate before calling

func sanitizeSessionID(id string) string {
    return strings.Map(func(r rune) rune {
        if unicode.IsControl(r) { return -1 }
        return r
    }, strings.TrimSpace(id))
}

Type guard

func printableSessionID(id string) bool {
    for _, r := range id {
        if unicode.IsControl(r) { return false }
    }
    return true
}

Try / catch

if err := key.Validate(); err != nil {
    if strings.Contains(err.Error(), "control characters") {
        key.SessionID = sanitizeSessionID(key.SessionID)
        return key.Validate()
    }
    return err
}

Prevention

When it happens

Trigger: Passing a SessionSandboxKey whose SessionID contains control runes (\n, \t, \x00, ...) to Validate, usually from raw header values, untrimmed input, or byte-level parsing mistakes.

Common situations: Session ID read from an HTTP header including a trailing newline; IDs split from a text blob retaining \r\n; accidental concatenation with NUL bytes.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/f4926f4927142a11. Report an issue: GitHub.