{"record":{"id":"a3b4a8c59e79cbd8","repo":"iflytek/astron-agent","slug":"s-must-contain-32-50-valid-utf-8-characters","errorCode":null,"errorMessage":"%s must contain 32-50 valid UTF-8 characters","messagePattern":"(.+?) must contain 32-50 valid UTF-8 characters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tenant/config/bootstrap_credentials.go","lineNumber":139,"sourceCode":"\t}\n\tif openedInfo.Size() > maxCredentialFileBytes {\n\t\treturn \"\", errors.New(\"credential file is too large\")\n\t}\n\n\tdata, err := io.ReadAll(io.LimitReader(file, maxCredentialFileBytes+1))\n\tif err != nil {\n\t\treturn \"\", errors.New(\"credential file cannot be read\")\n\t}\n\tif len(data) > maxCredentialFileBytes {\n\t\treturn \"\", errors.New(\"credential file is too large\")\n\t}\n\treturn strings.TrimSpace(string(data)), nil\n}\n\nfunc validateCredential(name, value string) error {\n\tlength := utf8.RuneCountInString(value)\n\tif !utf8.ValidString(value) || length < tenantCredentialMinLength || length > tenantCredentialMaxLength {\n\t\treturn fmt.Errorf(\"%s must contain 32-50 valid UTF-8 characters\", name)\n\t}\n\tfor _, character := range value {\n\t\tif unicode.IsControl(character) {\n\t\t\treturn fmt.Errorf(\"%s must not contain control characters\", name)\n\t\t}\n\t\tif !isSafeCredentialCharacter(character) {\n\t\t\treturn fmt.Errorf(\"%s must contain only ASCII letters, digits, '.', '_', '~', or '-'\", name)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc isSafeCredentialCharacter(character rune) bool {\n\treturn character >= 'a' && character <= 'z' ||\n\t\tcharacter >= 'A' && character <= 'Z' ||\n\t\tcharacter >= '0' && character <= '9' ||\n\t\tcharacter == '.' || character == '_' || character == '~' || character == '-'\n}","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/tenant/config/bootstrap_credentials.go#L121-L157","documentation":"validateCredential enforces that each bootstrap credential (TENANT_KEY/TENANT_SECRET) is valid UTF-8 and between 32 and 50 characters (rune count). 'must contain 32-50 valid UTF-8 characters' fires when the value is invalid UTF-8, shorter than 32, or longer than 50 runes.","triggerScenarios":"Validate or credentialFromEnvironmentOrFile calls validateCredential and the supplied value fails the length/UTF-8 check — e.g. a truncated env var, a base64 value pasted with extra characters, or binary/garbled bytes read from a file.","commonSituations":"Secret truncated by shell quoting or YAML parsing; value stored with a trailing newline counted before trim in a custom pipeline; ops pasted a hex key shorter than 32 chars; file encoding issue producing invalid UTF-8.","solutions":["Regenerate or re-copy the credential ensuring it is 32-50 characters of ASCII letters/digits/._~- .","Check for truncation: echo ${#TENANT_KEY} (or wc -m on the _FILE) and compare with the source secret.","Ensure the secret file is plain UTF-8 without BOM or binary content; re-create it with printf rather than editors that add bytes.","If using base64 secrets, decode before storing — the validator expects the raw value, not base64."],"exampleFix":"// before\nTENANT_KEY=abc123                # 6 chars, too short\n\n// after\nTENANT_KEY=7b709739e8da44536127a333c7603a83   # 32 chars (use a fresh non-legacy value)","handlingStrategy":"validation","validationCode":"func credentialLooksValid(v string) bool {\n\tn := utf8.RuneCountInString(v)\n\treturn utf8.ValidString(v) && n >= 32 && n <= 50\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check credential length (${#VAR}) when generating or rotating secrets.","Generate keys as exactly 32 hex characters to stay within bounds.","Never base64-encode unless you decode before injecting; the validator wants the raw value."],"tags":["validation","credentials","utf8","go"],"backgroundTag":"value-out-of-range","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}