{"record":{"id":"4b91b8fc43062f0a","repo":"github/copilot-sdk","slug":"copilotclient-mode-empty-requires-base-director","errorCode":null,"errorMessage":"CopilotClient(mode='empty') requires base_directory, session_fs, or a UriRuntimeConnection. Empty mode needs explicit per-tenant storage and won't fall back to ~/.copilot.","messagePattern":"CopilotClient\\(mode='empty'\\) requires base_directory, session_fs, or a UriRuntimeConnection\\. Empty mode needs explicit per-tenant storage and won't fall back to ~/\\.copilot\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/copilot/_mode.py","lineNumber":354,"sourceCode":"    if manage_schedule_enabled is not None:\n        patch[\"manageScheduleEnabled\"] = manage_schedule_enabled\n    if included_builtin_skills is not None:\n        patch[\"includedBuiltinSkills\"] = included_builtin_skills\n    return patch or None\n\n\ndef _require_storage_for_empty_mode(\n    *,\n    mode: CopilotClientMode | None,\n    base_directory: str | None,\n    session_fs_set: bool,\n    is_uri_connection: bool,\n) -> None:\n    if mode != \"empty\":\n        return\n    if base_directory or session_fs_set or is_uri_connection:\n        return\n    raise ValueError(\n        \"CopilotClient(mode='empty') requires base_directory, session_fs, \"\n        \"or a UriRuntimeConnection. Empty mode needs explicit per-tenant \"\n        \"storage and won't fall back to ~/.copilot.\"\n    )\n\n\ndef _require_available_tools_for_empty_mode(\n    mode: CopilotClientMode | None,\n    available_tools: list[str] | None,\n) -> None:\n    if mode == \"empty\" and available_tools is None:\n        raise ValueError(\n            \"CopilotClient is in mode='empty' but create_session was called \"\n            \"without available_tools. Empty mode requires every session to \"\n            \"explicitly opt into the tools it wants — e.g. \"\n            \"ToolSet().add_builtin(BUILTIN_TOOLS_ISOLATED).\"\n        )\n","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/_mode.py#L336-L372","documentation":"CopilotClient with mode='empty' provides no default storage: it is designed for per-tenant isolation and will not fall back to the shared ~/.copilot directory. Construction therefore fails unless the caller supplies explicit storage via base_directory, a session_fs config, or a UriRuntimeConnection.","triggerScenarios":"CopilotClient(mode='empty') constructed with no base_directory, no session_fs config, and no URI runtime connection — i.e. none of base_directory/session_fs_set/is_uri_connection is truthy in _require_storage_for_empty_mode during __init__.","commonSituations":"Developers switch from the default/'copilot-cli' mode to mode='empty' for multi-tenant use and forget that all default storage is disabled; sample code copied from default-mode docs omits the storage arguments.","solutions":["Pass base_directory='/path/to/tenant/storage' to CopilotClient","Or provide a session_fs config (see _validate_session_fs_config for its required fields)","Or supply a UriRuntimeConnection if storage is managed externally","If you do not need isolation, keep the default mode instead of mode='empty'"],"exampleFix":"// before\nclient = CopilotClient(mode=\"empty\")\n\n// after\nclient = CopilotClient(mode=\"empty\", base_directory=f\"/data/tenants/{tenant_id}\")","handlingStrategy":"validation","validationCode":"if mode == \"empty\" and not (base_directory or session_fs or uri_connection):\n    raise ValueError(\"mode='empty' requires base_directory, session_fs, or UriRuntimeConnection\")","typeGuard":"def empty_mode_has_storage(**kwargs) -> bool:\n    return bool(kwargs.get(\"base_directory\") or kwargs.get(\"session_fs\") or kwargs.get(\"uri_connection\"))","tryCatchPattern":"try:\n    client = CopilotClient(mode=\"empty\")\nexcept ValueError as e:\n    if \"requires base_directory\" in str(e):\n        client = CopilotClient(mode=\"empty\", base_directory=default_tenant_dir())","preventionTips":["Treat mode='empty' as opt-in isolation: always pair it with explicit storage","Use a factory function that injects base_directory per tenant","Never construct CopilotClient(mode='empty') from default-mode example code without adding storage args","Add an integration test constructing the client in empty mode with your real config"],"tags":["configuration","python","storage","client-init"],"backgroundTag":"missing-required-config","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}