infiniflow/ragflow · warning · Error

Failed to create search

Error message

Failed to create search

What it means

_run_with_timeout runs the OAuth helper in a daemon thread and joins with timeout_secs; if the thread is still alive (flow waiting on user consent in a browser) TimeoutError is raised with the given message. This guards headless/automated runs from hanging forever on the consent screen.

Source

Thrown at web/src/pages/next-searches/hooks.ts:53

interface CreateSearchResponse {
  id: string;
  name: string;
  description: string;
}

export const useCreateSearch = () => {
  const { t } = useTranslation();

  const {
    data,
    isError,
    mutateAsync: createSearchMutation,
  } = useMutation<CreateSearchResponse, Error, CreateSearchProps>({
    mutationKey: ['createSearch'],
    mutationFn: async (props) => {
      const { data: response } = await searchService.createSearch(props);
      if (response.code !== 0) {
        throw new Error(response.message || 'Failed to create search');
      }
      return response.data;
    },
    onSuccess: () => {
      message.success(t('message.created'));
    },
    onError: (error) => {
      message.error(t('message.error', { error: error.message }));
    },
  });

  const createSearch = useCallback(
    (props: CreateSearchProps) => {
      return createSearchMutation(props);
    },
    [createSearchMutation],
  );

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Re-run the flow from a machine with a working browser and port-forward localhost if remote (ssh -L 8080:localhost:8080)
  2. Complete the consent screen promptly once the URL appears; close stale tabs from earlier attempts first
  3. For fully headless setups, avoid the interactive flow entirely — use a service-account credential or paste a pre-minted token blob

Example fix

# before: headless box, nobody clicks consent
creds = _run_with_timeout(flow.run_local_server, timeout_secs=300, ...)  # TimeoutError

# after: run on a browser-capable host, or forward the callback port
# local:$ ssh -L 8080:localhost:8080 ci-host
# ci-host:$ python scripts/google_oauth_flow.py  # then click through locally
Defensive patterns

Strategy: try-catch

Validate before calling

import os, socket

def oauth_flow_env_ok() -> bool:
    # rough check: can we bind the callback port, is there a display/browser?
    try:
        s = socket.socket(); s.bind(("localhost", 0)); s.close()
        return os.environ.get("DISPLAY") is not None or os.environ.get("SSH_TUNNEL") == "1"
    except OSError:
        return False

Try / catch

try:
    token = run_oauth_with_timeout(flow, timeout_secs=300)
except TimeoutError:
    # no one completed consent — fall back to pre-minted token, don't loop
    token = json.loads(get_stored_token_blob())
    if not token:
        print("Run the flow from a machine with a browser (ssh -L 8080:localhost:8080).")

Prevention

When it happens

Trigger: Running the interactive local-server OAuth flow (or console fallback) where nobody completes the Google consent page within the timeout — typical in CI, containers, or SSH sessions without browser forwarding.

Common situations: Developer runs the token-generation script inside docker/CI, browser opens on the wrong machine, user steps away mid-consent, proxy blocking localhost:8080 callback.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/81886f87a584d8e0. Report an issue: GitHub.