{"record":{"id":"0548a28add9c56ff","repo":"vitessio/vitess","slug":"weightstringlen-called-with-non-mod4-length","errorCode":null,"errorMessage":"WeightStringLen called with non-MOD4 length","messagePattern":"WeightStringLen called with non-MOD4 length","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/mysql/collations/colldata/uca.go","lineNumber":216,"sourceCode":"\t\t\t}\n\t\t\thasher.Write(chunk[:16])\n\t\t}\n\t\thasher.Write(chunk[:n])\n\t\treturn\n\t}\n\n\tfor {\n\t\tw, ok := it.Next()\n\t\tif !ok {\n\t\t\tbreak\n\t\t}\n\t\thasher.Write16(bits.ReverseBytes16(w))\n\t}\n}\n\nfunc (c *Collation_utf8mb4_uca_0900) WeightStringLen(numBytes int) int {\n\tif numBytes%4 != 0 {\n\t\tpanic(\"WeightStringLen called with non-MOD4 length\")\n\t}\n\tlevels := int(c.uca.MaxLevel())\n\tweights := (numBytes / 4) * uca.MaxCollationElementsPerCodepoint * levels\n\tweights += levels - 1 // one NULL byte as a separator between levels\n\treturn weights * 2    // two bytes per weight\n}\n\nfunc (c *Collation_utf8mb4_uca_0900) Wildcard(pat []byte, matchOne rune, matchMany rune, escape rune) WildcardPattern {\n\t// The matcher must not take the Collate shortcut for literal patterns:\n\t// MySQL compares LIKE character by character and does not apply the\n\t// expansions and contractions that Collate applies, so 'ß' = 'ss' is\n\t// true and 'ß' LIKE 'ss' is false.\n\treturn newUnicodeWildcardMatcher(charset.Charset_utf8mb4{}, c.uca.WeightsEqual, nil, pat, matchOne, matchMany, escape)\n}\n\nfunc (c *Collation_utf8mb4_uca_0900) ToLower(dst, src []byte) []byte {\n\tdst = append(dst, bytes.ToLower(src)...)\n\treturn dst","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/collations/colldata/uca.go#L198-L234","documentation":"Collation_utf8mb4_uca_0900.WeightStringLen computes the maximum weight-string size for a UCA-900 collation. It assumes the input is a UTF-8 string whose byte length is a multiple of 4 (it divides by 4 to get codepoint count for the worst case of 3-byte codepoints... caller contract requires MOD4). If numBytes is not divisible by 4, the sizing arithmetic is invalid for this collation's expectations, so it panics rather than returning a wrong buffer size.","triggerScenarios":"Calling WeightStringLen(numBytes) on a Collation_utf8mb4_uca_0900 with numBytes not a multiple of 4 — typically passing a byte length from a non-utf8mb4 string, a truncated UTF-8 buffer, or a binary/varbinary value.","commonSituations":"Computing buffer sizes for weight strings on hand-built queries or binary columns routed to utf8mb4_uca_0900 collations; truncating string data mid-codepoint before hashing; migrating code from latin1 where byte lengths are never MOD4.","solutions":["Ensure the byte length passed is a multiple of 4 (pad or use the full utf8mb4 string length); for arbitrary strings use WeightString instead of WeightStringLen","Verify the data really is utf8mb4; if it may be truncated, use a rune-safe length (utf8.RuneCountInString * 4 rounded appropriately) before calling","If calling from engine code, only call WeightStringLen for exact-typing paths where length%4==0 is guaranteed (e.g. CHAR(4n) columns); otherwise fall back to the generic sizing path"],"exampleFix":"// before\nn := coll.WeightStringLen(len(b)) // panics when len(b)%4 != 0\n// after\nif len(b)%4 != 0 {\n\t// fall back to actual weight string computation\n\tw := make([]byte, coll.WeightStringMaxLen(len(b)))\n\tcoll.WeightString(b, w)\n} else {\n\tn := coll.WeightStringLen(len(b))\n}","handlingStrategy":"validation","validationCode":"if len(input)%4 != 0 {\n\t// do not call WeightStringLen; pad to a codepoint boundary or use WeightString\n}","typeGuard":"func isMod4(n int) bool { return n%4 == 0 }","tryCatchPattern":null,"preventionTips":["Only call WeightStringLen on guaranteed utf8mb4 CHAR-typed data","Prefer WeightString/WeightStringMaxLen for arbitrary-length inputs","Never truncate utf8mb4 buffers mid-codepoint before sizing"],"tags":["panic","collations","utf8","invalid-argument"],"backgroundTag":"weight-string-length-not-mod4","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}