{"record":{"id":"bd6806ff800bc042","repo":"pydantic/monty","slug":"one-character","errorCode":null,"errorMessage":"one character","messagePattern":"one character","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"crates/monty/src/modules/binascii.rs","lineNumber":501,"sourceCode":"/// CPython measures the length before it looks at the type, so an unsized\n/// separator reports \"has no len()\" and a sized one of the wrong length is a\n/// `ValueError` — \"sep must be str or bytes.\" only applies to a sized object\n/// of length one. `None` is not \"no separator\": omitting `sep` leaves it\n/// unset, so an explicit `None` fails the length check as any other object.\nfn hex_separator(sep: Option<&Value>, vm: &VM<'_>) -> RunResult<Option<u8>> {\n    let Some(sep) = sep else {\n        return Ok(None);\n    };\n    let length = sep\n        .py_len(vm)\n        .ok_or_else(|| ExcType::type_error(format!(\"object of type '{}' has no len()\", sep.py_type_name(vm))))?;\n\n    if length != 1 {\n        Err(value_error(\"sep must be length 1.\"))\n    } else if sep.is_str(vm.heap) {\n        // Latin-1, not ASCII: `hexlify` returns bytes, so CPython only rejects\n        // a character that does not fit a byte, under an \"ASCII\" message.\n        u8::try_from(u32::from(sep.to_str(vm)?.chars().next().expect(\"one character\")))\n            .map(Some)\n            .map_err(|_| value_error(\"sep must be ASCII.\"))\n    } else if is_bytes(sep, vm) {\n        Ok(Some(encode_input(sep, vm)?[0]))\n    } else {\n        Err(ExcType::type_error(\"sep must be str or bytes.\"))\n    }\n}\n\n/// Whether a value is `bytes`, which is all `hexlify` accepts as a separator\n/// besides `str` — a buffer that `encode_input` would take is still rejected.\nfn is_bytes(value: &Value, vm: &VM<'_>) -> bool {\n    match value {\n        Value::InternBytes(_) => true,\n        Value::Ref(heap_id) => matches!(vm.heap.get(*heap_id), HeapData::Bytes(_)),\n        _ => false,\n    }\n}","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/modules/binascii.rs#L483-L519","documentation":"Internal `expect('one character')` in `hex_separator`: it extracts the first char of a separator string already checked to have length exactly 1 (the `length != 1` guard raises `ValueError('sep must be length 1.')` beforehand), so `chars().next()` cannot be `None`. The user-facing failures here are the real `ValueError`s for wrong-length or non-ASCII separators, not this panic.","triggerScenarios":"Unreachable panics; the reachable errors are `ValueError: sep must be length 1.` (multi-char or empty sep) and `ValueError: sep must be ASCII.` (character above U+00FF) from `binascii.hexlify`.","commonSituations":"Users passing `sep='ab'`, `sep=''`, or a non-Latin-1 character (e.g. 'é' works as Latin-1, '€' fails) to `hexlify`.","solutions":["Pass a single-character ASCII (Latin-1 encodable) string or one-byte bytes as `sep`.","Check `len(sep) == 1` before calling if the separator is dynamic."],"exampleFix":"// before\nbinascii.hexlify(data, sep='ab')  # ValueError: sep must be length 1.\n// after\nbinascii.hexlify(data, sep=b'-')","handlingStrategy":"validation","validationCode":"if not isinstance(sep, (str, bytes)) or len(sep) != 1:\n    raise ValueError('sep must be length 1.')\nif isinstance(sep, str) and ord(sep) > 0xFF:\n    raise ValueError('sep must be ASCII.')","typeGuard":"def is_single_byte_sep(sep) -> bool:\n    if isinstance(sep, bytes):\n        return len(sep) == 1\n    return isinstance(sep, str) and len(sep) == 1 and ord(sep) <= 0xFF","tryCatchPattern":"try:\n    out = binascii.hexlify(data, sep=sep)\nexcept ValueError as exc:\n    # 'sep must be length 1.' or 'sep must be ASCII.'\n    handle_bad_separator(exc)","preventionTips":["Validate separator length and encodability before calling hexlify.","Prefer passing sep as bytes (b'-') to sidestep encoding questions.","For dynamic separators derived from user input, clamp with a allowlist of single ASCII characters."],"tags":["rust","internal-invariant","hexlify"],"backgroundTag":"internal-invariant-violation","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}