binary-husky/gpt_academic · error · RuntimeError

用户取消了程序。

Error message

用户取消了程序。

What it means

RuntimeError ('用户取消了程序。') from the Claude bridge's watchdog: while accumulating text from content_block_delta SSE events, the code checks observe_window[1], a UI-fed timestamp, against watch_dog_patience (5 s). If the timestamp goes stale during an active delta, the stream read is aborted as a user cancellation. Same cooperative-cancellation contract as the ChatGPT bridge, applied to Anthropic's event stream.

Source

Thrown at request_llms/bridge_claude.py:132

        need_to_pass, chunkjson, is_last_chunk = decode_chunk(chunk)
        if chunk:
            try:
                if need_to_pass:
                    pass
                elif is_last_chunk:
                    # logger.info(f'[response] {result}')
                    break
                else:
                    if chunkjson and chunkjson['type'] == 'content_block_delta':
                        result += chunkjson['delta']['text']
                        if observe_window is not None:
                            # 观测窗,把已经获取的数据显示出去
                            if len(observe_window) >= 1:
                                observe_window[0] += chunkjson['delta']['text']
                            # 看门狗,如果超过期限没有喂狗,则终止
                            if len(observe_window) >= 2:
                                if (time.time()-observe_window[1]) > watch_dog_patience:
                                    raise RuntimeError("用户取消了程序。")
            except Exception as e:
                chunk = get_full_error(chunk, stream_response)
                chunk_decoded = chunk.decode()
                error_msg = chunk_decoded
                logger.error(error_msg)
                raise RuntimeError("Json解析不合常规")

    return result

def make_media_input(history,inputs,image_paths):
    for image_path in image_paths:
        inputs = inputs + f'<br/><br/><div align="center"><img src="file={os.path.abspath(image_path)}"></div>'
    return inputs

def predict(inputs, llm_kwargs, plugin_kwargs, chatbot, history=[], system_prompt='', stream = True, additional_fn=None):
    """
    发送至chatGPT,流式获取输出。
    用于基础的对话功能。

View on GitHub (pinned to d6bde0fa54)

Solutions

  1. If intentional cancellation, simply send a new message.
  2. Keep the UI tab active and responsive so the watchdog keeps being fed.
  3. Custom callers: run a feeder thread updating observe_window[1] = time.time() every second during the whole stream.
  4. For consistently slow networks, increase watch_dog_patience in request_llms/bridge_claude.py.
Defensive patterns

Strategy: validation

Try / catch

try:
    result = predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window=win)
except RuntimeError as e:
    if '用户取消了程序' in str(e) and not user_cancelled:
        diagnose_ui_feeding()  # watchdog fired without a stop -> feed loop broken
    else:
        raise

Prevention

When it happens

Trigger: User presses stop in the Gradio UI while Claude is streaming; UI thread stops refreshing observe_window[1] (tab suspended, Gradio poll stalled); custom caller passes observe_window but never updates element [1] while content_block_delta events keep arriving.

Common situations: Deliberate mid-answer stops; mobile browsers backgrounding the page during long Claude generations; slow Anthropic responses combined with an unresponsive UI making the watchdog fire spuriously.

Related errors


AI-assisted analysis of binary-husky/gpt_academic@d6bde0fa54 (2026-08-14). Data as JSON: /api/errors/9746c1cafb199476. Report an issue: GitHub.