unclecode/crawl4ai · warning · ImportError

termios/tty/select modules not available on this platform

Error message

termios/tty/select modules not available on this platform

What it means

BrowserProfiler._listen_unix imports termios/tty/select and converts ImportError into this message. On Unix-likes these are stdlib and virtually always present; failure indicates a non-Unix platform (Windows) or a stripped Python build (termios excluded), i.e. the Unix listener was invoked where it cannot run.

Solutions

  1. Use the profiler's public interactive method which dispatches per OS.
  2. Gate manual calls: choose _listen_windows when sys.platform == 'win32'.
  3. On stripped Python builds, install a full CPython interpreter.

Example fix

# before
await profiler._listen_unix(event, check_proc, 'PROFILE')  # on Windows -> ImportError

# after
import sys
listener = profiler._listen_windows if sys.platform == 'win32' else profiler._listen_unix
await listener(event, check_proc, 'PROFILE')
Defensive patterns

Strategy: validation

Validate before calling

import sys
if sys.platform == 'win32':
    raise OSError('Unix keyboard listener requires a Unix-like platform')

Type guard

import sys
def is_unix() -> bool:
    return sys.platform != 'win32'

Prevention

When it happens

Trigger: Calling _listen_unix() on Windows; a minimal/embedded Python build compiled without termios; unusual environments like some WASM/pyodide runtimes that lack termios.

Common situations: Cross-platform code calling the private listener without a platform check; exotic Python distributions; test harnesses invoking internals on the wrong OS.

Related errors


AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14). Data as JSON: /api/errors/439252b23de69c4f. Report an issue: GitHub.

Appendix: source

Thrown at crawl4ai/browser_profiler.py:259

                    return
                
                # Small delay to prevent busy waiting
                await asyncio.sleep(0.1)
                
            except Exception as e:
                self.logger.warning(f"Error in Windows keyboard listener: {e}", tag=tag)
                # Continue trying instead of failing completely
                await asyncio.sleep(0.1)
                continue
    
    async def _listen_unix(self, user_done_event: asyncio.Event, check_browser_process, tag: str):
        """Unix/Linux/macOS keyboard listener using termios and select."""
        try:
            import termios
            import tty
            import select
        except ImportError:
            raise ImportError("termios/tty/select modules not available on this platform")
        
        # Get stdin file descriptor
        try:
            fd = sys.stdin.fileno()
        except (AttributeError, OSError):
            raise ImportError("stdin is not a terminal")
        
        # Save original terminal settings
        old_settings = None
        try:
            old_settings = termios.tcgetattr(fd)
        except termios.error as e:
            raise ImportError(f"Cannot get terminal attributes: {e}")
        
        try:
            # Switch to non-canonical mode (cbreak mode)
            tty.setcbreak(fd)
            

View on GitHub (pinned to 7e80152142)