#7656·textgen

Bug: Empty JSON chat history files cause JSONDecodeError (very rare)

Author: Pub-PolarisCreated Sep 9, 2026Updated Sep 10, 2026
Labelsbug

Describe the bug

When using text-generation-webui with a remote llama.cpp server (http://192.168.1.24:12546/), 0-byte JSON files are created in user_data/logs/chat/<character>/ and user_data/logs/instruct/. Attempting to list chat histories or load a session throws: json.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Summary of Code Changes (How to fixed it) Here are the three fixes applied to G:\textgen-main\modules\chat.py to handle empty/0-byte JSON chat history files:

  1. find_all_histories_with_first_prompts (lines 1903-1904) Purpose: Skip empty JSON files when listing chat histories for the UI sidebar.
if not file_content:
    continue

Added after reading file content, before searching. Prevents empty files from appearing in history list.

  1. load_history (lines 2043-2045) Purpose: Gracefully handle empty JSON files when loading a specific chat session.
with open(p, 'rb') as fh:
    content = fh.read()
if not content:
    return {'internal': [], 'visible': [], 'metadata': {}}
f = json.loads(content)

Returns empty history structure instead of raising json.JSONDecodeError on 0-byte files.

  1. load_history_json (lines 2071-2072) Purpose: Handle empty file uploads/imports in the chat history import feature.
if not file.strip():
    return history

Returns original history unchanged if uploaded file is empty/whitespace.

Is there an existing issue for this?

  • I have searched the existing issues

Reproduction

None

Specific Circumstances

This issue occurs specifically when:

  1. Using a llama.cpp server via the --llama-cpp-server flag or API endpoint configuration (?) ,or loading/create a new char/chat on a remote device.
  2. Starting a new chat session with a character - the server creates a placeholder JSON file before the first.message exchange
  3. Network interruption or timeout during the first model response - leaves a 0-byte file that never gets written to.
  4. Switching characters/models mid-session - triggers new history file creation that may remain empty if the switch fails.
  5. High latency connections to the llama.cpp server (>5s response time) where the UI creates the history file but the request times out before content is written.

The issue does not occur with:

  • Local model loading (transformers, GGUF via llama.cpp Python bindings, ExLlamaV2, etc.)
  • Completed chat sessions that have at least one message exchange
  • Fresh installations with no prior chat history

Fix Applied

Three defensive checks added to modules/chat.py:

  1. find_all_histories_with_first_prompts (line 1903-1904): Skip empty files when building history list
  2. load_history (lines 2043-2045): Return empty history struct instead of crashing on empty file
  3. load_history_json (lines 2071-2072): Ignore empty uploaded history files

Files Changed

  • modules/chat.py: Added 3 guard clauses for empty file handling

Screenshot

⚠️ AI-Assisted Fix Disclaimer This fix was written with AI assistance. I do not have programming expertise to fully verify the correctness and completeness of these changes. Please review and test thoroughly before merging. Specifically:

  • The fix handles the symptom (empty files) but may not address why llama.cpp creates 0-byte files in the first place
  • Edge cases around concurrent file access or race conditions may exist
  • The background cleanup script is a workaround, not a root cause fix
  • Community testing with various llama.cpp server versions and configurations is needed
  • Due to that, I won't push that codes changed to PR

Your verification and feedback are greatly appreciated.

Logs

Traceback (most recent call last):
  File "G:\textgen-main\installer_files\env\Lib\site-packages\gradio\queueing.py", line 549, in process_events
    response = await route_utils.call_process_api(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<5 lines>...
    )
    ^
  File "G:\textgen-main\installer_files\env\Lib\site-packages\gradio\route_utils.py", line 276, in call_process_api
    output = await app.get_blocks().process_api(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<11 lines>...
    )
    ^
  File "G:\textgen-main\installer_files\env\Lib\site-packages\gradio\blocks.py", line 1904, in process_api
    result = await self.call_function(
             ^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<8 lines>...
    )
    ^
  File "G:\textgen-main\installer_files\env\Lib\site-packages\gradio\blocks.py", line 1490, in call_function
    prediction = await anyio.to_thread.run_sync(
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        fn, *processed_input, limiter=self.limiter
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "G:\textgen-main\installer_files\env\Lib\site-packages\anyio\to_thread.py", line 63, in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        func, args, abandon_on_cancel=abandon_on_cancel, limiter=limiter
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "G:\textgen-main\installer_files\env\Lib\site-packages\anyio\_backends\_asyncio.py", line 2518, in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
  File "G:\textgen-main\installer_files\env\Lib\site-packages\anyio\_backends\_asyncio.py", line 1002, in run
    result = context.run(func, *args)
  File "G:\textgen-main\installer_files\env\Lib\site-packages\gradio\\\utils.py", line 812, in wrapper
    response = f(*args, **kwargs)
  File "G:\textgen-main\modules\chat.py", line 2546, in handle_start_new_chat_click
    histories = find_all_histories_with_first_prompts(state)
  File "G:\textgen-main\modules\chat.py", line 1906, in find_all_histories_with_first_prompts
    data = json.loads(file_content)
  File "G:\textgen-main\installer_files\env\Lib\json\__init__.py", line 352, in loads
    return _default_decoder.decode(s)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^
  File "G:\textgen-main\installer_files\env\Lib\json\decoder.py", line 345, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "G:\textgen-main\installer_files\env\Lib\json\decoder.py", line 363, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

System Info

Windows 11 Pro Workstation
Gunnir Intel Arc B580 Graphics
Intel i5-14600k