Skip to content

Connection exception during transfer does not always retry #339

Description

@bjester

Target branch: release-v0.8.x

Context

Morango's sync session controller uses the Retry mechanism of python requests.

Observed behavior

If connection interruptions cause a malformed response, errors like ProtocolError can cause the sync transfer to all out fail. This could occur due to low or flaky connectivity.

Errors and logs

ERROR 2026-06-09 11:38:18,722 morango.sync.session ChunkedEncodingError Reason: (no response)
ERROR 2026-06-09 11:38:18,722 morango.sync.controller ("Connection broken: InvalidChunkLength(got length b'', 0 bytes read)", InvalidChunkLength(got length b'', 0 bytes read))
INFO 2026-06-09 11:38:18,737 kolibri.core.auth.management.utils Receiving data (14600/111908, 54.25MB)
ERROR 2026-06-09 11:38:18,779 kolibri.core.tasks.job Job fd71f20d5dee4747bb22320c39c1f4b3 raised an exception: Traceback (most recent call last):
  File "C:\Python38\Lib\site-packages\kolibri\dist\urllib3\response.py", line 761, in _update_chunk_length
    self.chunk_left = int(line, 16)
ValueError: invalid literal for int() with base 16: b''

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python38\Lib\site-packages\kolibri\dist\urllib3\response.py", line 444, in _error_catcher
    yield
  File "C:\Python38\Lib\site-packages\kolibri\dist\urllib3\response.py", line 828, in read_chunked
    self._update_chunk_length()
  File "C:\Python38\Lib\site-packages\kolibri\dist\urllib3\response.py", line 765, in _update_chunk_length
    raise InvalidChunkLength(self, line)
urllib3.exceptions.InvalidChunkLength: InvalidChunkLength(got length b'', 0 bytes read)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python38\Lib\site-packages\kolibri\dist\requests\models.py", line 760, in generate
    for chunk in self.raw.stream(chunk_size, decode_content=True):
  File "C:\Python38\Lib\site-packages\kolibri\dist\urllib3\response.py", line 624, in stream
    for line in self.read_chunked(amt, decode_content=decode_content):
  File "C:\Python38\Lib\site-packages\kolibri\dist\urllib3\response.py", line 857, in read_chunked
    self._original_response.close()
  File "c:\python38\lib\contextlib.py", line 131, in __exit__
    self.gen.throw(type, value, traceback)
  File "C:\Python38\Lib\site-packages\kolibri\dist\urllib3\response.py", line 461, in _error_catcher
    raise ProtocolError("Connection broken: %r" % e, e)
urllib3.exceptions.ProtocolError: ("Connection broken: InvalidChunkLength(got length b'', 0 bytes read)", InvalidChunkLength(got length b'', 0 bytes read))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python38\Lib\site-packages\kolibri\dist\morango\sync\controller.py", line 254, in _invoke_middleware
    result = middleware(prepared_context)
  File "C:\Python38\Lib\site-packages\kolibri\dist\morango\registry.py", line 204, in __call__
    result = operation(context)
  File "C:\Python38\Lib\site-packages\kolibri\dist\morango\sync\operations.py", line 982, in __call__
    result = self.handle(context)
  File "C:\Python38\Lib\site-packages\kolibri\dist\morango\sync\operations.py", line 1683, in handle
    data = self.get_buffers(context)
  File "C:\Python38\Lib\site-packages\kolibri\dist\morango\sync\operations.py", line 1412, in get_buffers
    response = context.connection._pull_record_chunk(context.transfer_session)
  File "C:\Python38\Lib\site-packages\kolibri\dist\morango\sync\syncsession.py", line 513, in _pull_record_chunk
    return self.session.get(self.urlresolve(api_urls.BUFFER), params=params)
  File "C:\Python38\Lib\site-packages\kolibri\dist\requests\sessions.py", line 542, in get
    return self.request('GET', url, **kwargs)
  File "C:\Python38\Lib\site-packages\kolibri\dist\morango\sync\session.py", line 77, in request
    raise req_err
  File "C:\Python38\Lib\site-packages\kolibri\dist\morango\sync\session.py", line 52, in request
    response = super(SessionWrapper, self).request(method, url, **kwargs)
  File "C:\Python38\Lib\site-packages\kolibri\dist\requests\sessions.py", line 529, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Python38\Lib\site-packages\kolibri\dist\requests\sessions.py", line 687, in send
    r.content
  File "C:\Python38\Lib\site-packages\kolibri\dist\requests\models.py", line 838, in content
    self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b''
  File "C:\Python38\Lib\site-packages\kolibri\dist\requests\models.py", line 763, in generate
    raise ChunkedEncodingError(e)
requests.exceptions.ChunkedEncodingError: ("Connection broken: InvalidChunkLength(got length b'', 0 bytes read)", InvalidChunkLength(got length b'', 0 bytes read))

Expected behavior

Errors that are related to low level connection issues, like the documented one, should cause Morango to retry the request. This is especially useful during the transferring stage, when a transfer response is corrupted due to connection issues. Ideally, this leverages the same Retry mechanism used with the requests library, performing an exponential backoff for retries up to the already configured retry limit.

User-facing consequences

For users who are performing syncs over brittle connections, this requires manual intervention to resume a sync where it left off. Ideally, syncs do the very best to retry whenever possible, up to a reasonable limit, to avoid manual intervention as much as possible.

Steps to reproduce

No clear pathway to reproduce without significant effort

Context

Morango 0.8.10 (at least)
Kolibri 0.19.1

Metadata

Metadata

Assignees

Type

No fields configured for Bug.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions