{"record":{"id":"4365ac0c679294ae","repo":"langchain-ai/deepagents","slug":"extension-factory-in-source-path-attempted-to-ex","errorCode":null,"errorMessage":"Extension factory in {source.path} attempted to exit: {exc}","messagePattern":"Extension factory in (.+?) attempted to exit: (.+?)","errorType":"exception","errorClass":"ExtensionError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/extensions/loader.py","lineNumber":109,"sourceCode":"    snapshot = registry._snapshot()\n    api = ExtensionAPI(registry, source, cwd=cwd, mode=mode)\n    try:\n        await factory(api)\n    except (KeyboardInterrupt, asyncio.CancelledError):\n        registry._rollback(snapshot)\n        api._deactivate()\n        sys.modules.pop(name, None)\n        raise\n    except (SystemExit, Exception) as exc:\n        registry._rollback(snapshot)\n        api._deactivate()\n        sys.modules.pop(name, None)\n        msg = (\n            f\"Extension factory in {source.path} attempted to exit: {exc}\"\n            if isinstance(exc, SystemExit)\n            else f\"Extension factory in {source.path} failed: {exc}\"\n        )\n        raise ExtensionError(msg) from exc\n    return api\n","sourceCodeStart":91,"sourceCodeEnd":111,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/extensions/loader.py#L91-L111","documentation":"Raised by `load_extension` when the extension factory calls `sys.exit()` (or otherwise raises `SystemExit`) during loading. The loader treats a factory attempting to terminate the host process as a defect and converts it into an `ExtensionError` chained from the original exception.","triggerScenarios":"A factory body calls `sys.exit(1)`, `raise SystemExit`, `argparse`'s `parse_args()` exits on bad args, or `click`/`typer` CLI helpers that call `sys.exit` are invoked at import/factory time.","commonSituations":"Extensions reusing CLI argument-parsing code during initialization; defensive `sys.exit` on missing optional deps written for standalone scripts; copy-pasted script boilerplate inside the factory.","solutions":["Remove any `sys.exit()`/`SystemExit` from the factory; raise a normal `Exception` instead","Replace eager `argparse.parse_args()` calls in the factory with lazy parsing at command-invocation time","On missing dependencies, raise `ImportError`/return an error rather than exiting"],"exampleFix":"// before\nasync def extension(api):\n    if not shutil.which(\"rg\"):\n        sys.exit(\"ripgrep is required\")\n\n// after\nasync def extension(api):\n    if not shutil.which(\"rg\"):\n        raise RuntimeError(\"ripgrep is required for the search extension\")","handlingStrategy":"try-catch","validationCode":"import ast, sys\nfor node in ast.walk(ast.parse(open(path).read())):\n    if isinstance(node, ast.Call) and getattr(node.func, 'attr', '') == 'exit':\n        raise SystemExit(f\"{path} calls sys.exit inside factory\")","typeGuard":null,"tryCatchPattern":"try:\n    api = await load_extension(source, registry)\nexcept ExtensionError as exc:\n    logger.error(\"extension tried to exit: %s\", exc)  # original cause in exc.__cause__","preventionTips":["Never call sys.exit() inside extension factories","Avoid argparse/click parse_args() at factory time","Raise descriptive exceptions instead of exiting the process"],"tags":["extensions","systemexit","plugin-loading"],"backgroundTag":"plugin-calls-sys-exit","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}