cloudreve/cloudreve · warning · ErrBadUTF7
utf7: bad utf-7 encoding
Error message
utf7: bad utf-7 encoding
What it means
wopi.ErrBadUTF7 signals invalid modified UTF-7 encoding while decoding (or encoding) strings. Modified UTF-7 (mUTF-7, the IMAP mailbox encoding) represents non-printable characters as base64 blocks delimited by '&' and terminating '-'; the decoder rejects malformed blocks, bad base64 characters, unterminated shifted sequences, or values that decode to invalid code points.
Source
Thrown at pkg/wopi/utf7.go:80
}
func (e *simpleEncoding) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: e.Decoder}
}
func (e *simpleEncoding) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{Transformer: e.Encoder}
}
var (
UTF7 encoding.Encoding = &simpleEncoding{
utf7Decoder{},
utf7Encoder{},
}
)
// ErrBadUTF7 is returned to indicate invalid modified UTF-7 encoding.
var ErrBadUTF7 = errors.New("utf7: bad utf-7 encoding")
// Base64 codec for code points outside of the 0x20-0x7E range.
const modifiedbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
var u7enc = base64.NewEncoding(modifiedbase64)
func isModifiedBase64(r byte) bool {
if r >= 'A' && r <= 'Z' {
return true
} else if r >= 'a' && r <= 'z' {
return true
} else if r >= '0' && r <= '9' {
return true
} else if r == '+' || r == '/' {
return true
}
return false
// bs := []byte(modifiedbase64)View on GitHub (pinned to 20c95ad73f)
Solutions
- Send the field as proper modified UTF-7 (&base64-) or plain ASCII, not raw UTF-8 with stray '&' characters
- Escape literal '&' in mUTF-7 content as '&-'
- Decode with UTF7.Decoder and treat ErrBadUTF7 as 'fall back to treating the input as UTF-8/ASCII'
- Log the raw bytes on failure to identify double-encoding
Example fix
// before
name, err := UTF7.NewDecoder().String(raw) // raw is actually UTF-8 -> may hit ErrBadUTF7
if err != nil { return err }
// after
name, err := UTF7.NewDecoder().String(raw)
if errors.Is(err, ErrBadUTF7) {
name = raw // input was not mUTF-7; treat as UTF-8
} else if err != nil {
return err
} Defensive patterns
Strategy: fallback
Validate before calling
// Cheap sanity check: only decode as mUTF-7 when '&' shifted sections look well-formed
func looksLikeMUTF7(s string) bool {
inShift := false
for i := 0; i < len(s); i++ {
switch {
case s[i] == '&':
if inShift { return false }
inShift = true
case s[i] == '-':
inShift = false
case inShift && !isModifiedBase64Byte(s[i]):
return false
}
}
return !inShift // unterminated shift section is invalid
} Try / catch
// Fall back to UTF-8 when mUTF-7 decoding fails
name, err := UTF7.NewDecoder().String(raw)
if errors.Is(err, ErrBadUTF7) {
name = raw // client sent UTF-8/ASCII; use as-is
} else if err != nil {
return err
} Prevention
- Escape literal '&' as '&-' when producing mUTF-7
- Keep WOPI integration strings in one encoding end-to-end; log raw bytes on the first failure
- Reject mUTF-7 encoder input containing '&' unless it is an intentional escape
When it happens
Trigger: A WOPI client sends a filename or mailbox-style path encoded in modified UTF-7 where a '&' shifted section contains characters outside the modified base64 alphabet, is never closed with '-', decodes to a rune sequence with surrogate issues, or the encoder is handed a rune it cannot represent. Decoding a plain UTF-8 string that happens to contain '&' followed by base64-looking characters also trips it.
Common situations: Integrating a WOPI office suite that URL-encodes names differently than expected; filenames with emoji/CJK characters double-encoded (UTF-8 bytes fed to the mUTF-7 decoder); protocol middleware corrupting '&' characters; clients sending UTF-7 where UTF-8 was required.
AI-assisted analysis of cloudreve/cloudreve@20c95ad73f (2026-08-16).
Data as JSON: /api/errors/bde99dd39e81c5d6.
Report an issue: GitHub.