`twine upload --verbose` hangs indefinitely in CI due to Rich bug with BOM character in response
envgap__pypa__twine-1302
01 / FAILURE SIGNATURE
As reported upstream
- [x] I have searched the existing issues (open and closed), and could not find an existing issue
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
ac17a17a9c01c5a2ba10f6ee142cef5aec6f56b0- Manifest
pyproject.toml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / ORIGINAL ISSUE TEXT
pypa/twine #1302 · read the original issue
### Is there an existing issue for this?
- [x] I have searched the existing issues (open and closed), and could not find an existing issue
### What keywords did you use to search existing issues?
rich
BOM
### What operating system are you using?
Linux
### If you selected 'Other', describe your Operating System here
_No response_
### What version of Python are you running?
```console
$ python --version
Python 3.9.25
```
### How did you install twine? Did you use your operating system's package manager or pip or something else?
```console
$ pip install twine
```
### What version of twine do you have installed (include the complete output)
```console
$ twine --version
twine version 6.2.0 (keyring: 25.7.0, packaging: 26.0, requests: 2.32.5, requests-toolbelt: 1.0.0, urllib3: 2.6.3, id: 1.5.0, importlib-metadata:
8.7.1)
```
### Which package repository are you using?
https://pypi.org/simple/
### Please describe the issue that you are experiencing
`twine upload --verbose` hangs indefinitely in non-TTY environments (e.g. CI pipelines) when the server response body starts with a UTF-8 BOM character (`\ufeff`). This occurs when uploading to Azure DevOps Artifacts with an expired PAT. The process produces no error output and must be manually killed.
The root cause is a bug in Rich < 14.3.3 where `RichHandler` enters an infinite loop in `split_graphemes`/`chop_cells` when word-wrapping text containing a BOM character ([fixed in Rich 14.3.3](https://github.com/Textualize/rich/releases/tag/v14.3.3)). Twine's current dependency of `rich >= 12.0.0` allows the buggy versions.
**Suggested fix:** Bump minimum Rich dependency to `rich >= 14.3.3` in `pyproject.toml`.
### Please list the steps required to reproduce this behaviour
1. Install twine 6.2.0 with rich 14.3.1 (actually any rich < 14.3.3)
2. Run the following minimal reproduction without a TTY:
```python
import rich.logging, logging
handler = rich.logging.RichHandler(show_time=False, show_path=False)
logger = logging.getLogger("test")
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.info('\ufeff' + 'x' * 400)
print("Done") # Never reached
```
```bash
python3 mre.py < /dev/null 2>&1 | cat
```
3. Or reproduce via twine directly — upload to a server that returns a BOM-prefixed response (e.g. Azure DevOps Artifacts with an expired PAT):
```bash
twine upload --repository-url https://pkgs.dev.azure.com/<org>/<project>/_packaging/<feed>/pypi/upload -u <user> -p <expired-PAT> --verbose dist/*
```
Without `--verbose`, twine fails correctly. With `--verbose`, it hangs after printing `401 Unauthorized`.
### Anything else you'd like to mention?
Fixed by upgrading to rich >= 14.3.3 (https://github.com/Textualize/rich/releases/tag/v14.3.3)04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]