iflytek/astron-agent · error
must not contain control characters
Error message
%s must not contain control characters
What it means
After the length/UTF-8 check, validateCredential iterates the value and rejects any control character (unicode.IsControl), such as \n, \r, or \t. The credential is placed in HTTP headers and storage, so embedded control characters are forbidden. The message names which variable (TENANT_KEY or TENANT_SECRET) contained them.
Solutions
- Rewrite the secret file without trailing newline/control chars: printf '%s' "$VALUE" > file (use printf, not echo).
- Convert CRLF to LF: dos2unix on the secret file, or regenerate it on Linux.
- Ensure the secret is a single line with only ASCII letters, digits, and . _ ~ - characters.
- If the value legitimately contained newlines, it is the wrong secret — retrieve the correct single-line credential.
Example fix
// before echo "$TENANT_KEY" > /run/secrets/tenant-key # adds trailing \n // after printf '%s' "$TENANT_KEY" > /run/secrets/tenant-key
Defensive patterns
Strategy: validation
Validate before calling
func hasControlChars(v string) bool {
for _, r := range v {
if unicode.IsControl(r) { return true }
}
return false
} Prevention
- Write secret files with printf '%s', never echo (which appends a newline).
- Run dos2unix or generate secrets on Linux to avoid CRLF.
- Use single-line string values (not block scalars) in YAML secrets.
When it happens
Trigger: A credential value read from a file or pasted into an env var contains a trailing/interior newline, carriage return (Windows CRLF), tab, or other control byte, and validateCredential reaches the control-character branch.
Common situations: Secret file created on Windows with CRLF line endings; echo instead of printf -n when writing the secret file; multi-line paste into a Kubernetes Secret; YAML block scalar (|) adding a trailing newline (though readCredentialFile trims edges, interior newlines still fail).
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.
Related errors
- TENANT_ID must remain
- must contain 32-50 valid UTF-8 characters
- must contain only ASCII letters, digits, '.', '_', '~', or
- Remote resource URL must not include user information
- TENANT_KEY and TENANT_SECRET must be distinct values
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/ad7786d24b92e46a.
Report an issue: GitHub.
Appendix: source
Thrown at core/tenant/config/bootstrap_credentials.go:143
data, err := io.ReadAll(io.LimitReader(file, maxCredentialFileBytes+1))
if err != nil {
return "", errors.New("credential file cannot be read")
}
if len(data) > maxCredentialFileBytes {
return "", errors.New("credential file is too large")
}
return strings.TrimSpace(string(data)), nil
}
func validateCredential(name, value string) error {
length := utf8.RuneCountInString(value)
if !utf8.ValidString(value) || length < tenantCredentialMinLength || length > tenantCredentialMaxLength {
return fmt.Errorf("%s must contain 32-50 valid UTF-8 characters", name)
}
for _, character := range value {
if unicode.IsControl(character) {
return fmt.Errorf("%s must not contain control characters", name)
}
if !isSafeCredentialCharacter(character) {
return fmt.Errorf("%s must contain only ASCII letters, digits, '.', '_', '~', or '-'", name)
}
}
return nil
}
func isSafeCredentialCharacter(character rune) bool {
return character >= 'a' && character <= 'z' ||
character >= 'A' && character <= 'Z' ||
character >= '0' && character <= '9' ||
character == '.' || character == '_' || character == '~' || character == '-'
}
View on GitHub (pinned to 5e758547a8)