AlistGo/alist · error
failed to decode hex_inner: %w
Error message
failed to decode hex_inner: %w
What it means
During step 3 SSO login, the 'data' field extracted from the first decryption layer was expected to be a hex-encoded AES-ECB ciphertext, but hex.DecodeString rejected it. The server returned a data blob that is not hex — usually because the first-layer response was an error message rather than the login payload.
Source
Thrown at drivers/139/util.go:1223
"User-Agent": "okhttp/3.12.2",
}, KEY_HEX_1, nil)
if err != nil {
return "", fmt.Errorf("step3 encrypted request failed: %w", err)
}
hexInner := jsoniter.Get(decryptedLayer1StrBytes, "data").ToString()
if hexInner == "" {
return "", errors.New("missing data field in first layer decryption result")
}
log.Debugf("DEBUG: 第一层解密提取到 hex_inner, length=%d", len(hexInner))
key2, err := hex.DecodeString(KEY_HEX_2)
if err != nil {
return "", fmt.Errorf("failed to decode KEY_HEX_2: %w", err)
}
hexInnerBytes, err := hex.DecodeString(hexInner)
if err != nil {
return "", fmt.Errorf("failed to decode hex_inner: %w", err)
}
finalJsonStrBytes, err := aesEcbDecrypt(hexInnerBytes, key2)
if err != nil {
return "", fmt.Errorf("step3 response layer2 aes ecb decrypt failed: %w", err)
}
log.Debugf("DEBUG: third party login response decrypted.")
authToken := jsoniter.Get(finalJsonStrBytes, "authToken").ToString()
if authToken == "" {
return "", errors.New("failed to extract authToken from final decryption result")
}
account := jsoniter.Get(finalJsonStrBytes, "account").ToString()
userDomainId := jsoniter.Get(finalJsonStrBytes, "userDomainId").ToString()
if account == "" || userDomainId == "" {
return "", errors.New("failed to extract account or userDomainId from final decryption result")
}
View on GitHub (pinned to 843d9dc814)
Solutions
- Log the hexInner string content and compare with a capture from the official android client
- Refresh credentials/cookies and retry — stale session state often makes the server answer with a non-payload body
- Update OpenList to the latest version where the layered SSO scheme is maintained in sync with the mobile app
- If maintaining a fork, hex-validate with a lenient decoder to identify what encoding the field actually switched to
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: reject non-hex data before decryption attempt
if !isHex(hexInner) {
return fmt.Errorf("data field is not hex: %q", truncate(hexInner, 32))
} Type guard
func isHex(s string) bool {
if len(s)%2 != 0 { return false }
for _, c := range s {
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { return false }
}
return true
} Try / catch
// Classify as protocol drift and capture the payload; do not retry blind
if strings.Contains(err.Error(), "failed to decode hex_inner") {
log.Printf("layer-1 data field not hex — protocol change suspected")
return err
} Prevention
- Log the data field content when it fails hex validation
- Track 139 app version changes; the layered hex/ECB scheme changes with app updates
- Maintain a fork-ready location for the SSO constants so patches are one-line
When it happens
Trigger: jsoniter extracted a non-empty 'data' field, but it contains non-hex characters (e.g. a base64 string, a URL, or an error description) because the SSO request was rejected upstream.
Common situations: Protocol drift after a 139 app update changing the inner encoding, expired step-2 token producing an error body that still has a 'data' field, or partial response corruption.
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
- cannot get username from SSO provider
- sso login is disabled
- invalid request
- error occurred
- step3 response layer2 aes ecb decrypt failed: %w
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/74a5b7b14dc9d9c3.
Report an issue: GitHub.