larksuite/cli · error

%s contains dangerous Unicode characters

Error message

%s contains dangerous Unicode characters

What it means

ResourceName iterates the identifier's runes and rejects any character for which charcheck.IsDangerousUnicode returns true — e.g. bidi controls, zero-width, or homoglyph-confusable characters. This stops visually deceptive or control-bearing IDs from being sent to the API. The flag name identifies which input to correct.

Source

Thrown at internal/validate/resource.go:41

//
// Without this check, an input like "../admin" or "?evil=true" in a message ID
// would alter the API endpoint the request is sent to. Works alongside
// EncodePathSegment for defense-in-depth.
func ResourceName(name, flagName string) error {
	if name == "" {
		return fmt.Errorf("%s must not be empty", flagName)
	}
	for _, seg := range strings.Split(name, "/") {
		if seg == ".." {
			return fmt.Errorf("%s must not contain '..' path traversal", flagName)
		}
	}
	if unsafeResourceChars.MatchString(name) {
		return fmt.Errorf("%s contains invalid characters", flagName)
	}
	for _, r := range name {
		if charcheck.IsDangerousUnicode(r) {
			return fmt.Errorf("%s contains dangerous Unicode characters", flagName)
		}
	}
	return nil
}

// EncodePathSegment percent-encodes user input for safe use as a single URL path
// segment (e.g. / → %2F, ? → %3F, # → %23), ensuring the value cannot alter the
// URL routing structure when interpolated into an API path.
//
// This provides defense-in-depth alongside ResourceName: ResourceName rejects known
// dangerous patterns at the input layer, while EncodePathSegment acts as a fallback
// at the concatenation layer — if ResourceName rules are relaxed in the future, or
// if an API path bypasses ResourceName validation (e.g. cmd/service/ generic calls),
// encoding still prevents special characters from being interpreted as path separators
// or query parameters.
//
// Convention: all user-provided variables in fmt.Sprintf API paths within shortcuts/
// MUST be wrapped with this function.

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Re-copy the ID from a plain-text source (terminal, API JSON) rather than rich text.
  2. Strip invisible characters with a Unicode-stripping filter before use.
  3. Fetch the canonical ID again via the API (list/search) instead of pasting.
  4. Inspect the input with `hexdump -C` to find hidden characters.

Example fix

// before
lark-cli im message get --message-id "$ID"   # ID copied from a doc, contains U+200B
// after
ID=$(printf '%s' "$ID" | perl -CS -pe 's/[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{FEFF}]//g')
lark-cli im message get --message-id "$ID"
Defensive patterns

Strategy: validation

Validate before calling

for _, r := range id {
    if charcheck.IsDangerousUnicode(r) {
        return fmt.Errorf("id contains dangerous Unicode (bidi/zero-width) characters")
    }
}

Try / catch

if err := validate.ResourceName(id, "--message-id"); err != nil {
    return fmt.Errorf("re-copy the id from a plain-text source: %w", err)
}

Prevention

When it happens

Trigger: validate.ResourceName receives a name containing dangerous Unicode (bidi/zero-width/control characters), detected per-rune via charcheck.IsDangerousUnicode.

Common situations: IDs copy-pasted from rich-text documents or chat messages carrying invisible formatting characters, CSV/spreadsheet exports with BOM or zero-width spaces, or crafted spoofed identifiers.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/dd7c44e61dfac011. Report an issue: GitHub.