github/copilot-sdk · error · ValueError
CopilotClient(mode='empty') requires base_directory…
Error message
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.
What it means
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.
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'
Example fix
// before
client = CopilotClient(mode="empty")
// after
client = CopilotClient(mode="empty", base_directory=f"/data/tenants/{tenant_id}") Defensive patterns
Strategy: validation
Validate before calling
if mode == "empty" and not (base_directory or session_fs or uri_connection):
raise ValueError("mode='empty' requires base_directory, session_fs, or UriRuntimeConnection") Type guard
def empty_mode_has_storage(**kwargs) -> bool:
return bool(kwargs.get("base_directory") or kwargs.get("session_fs") or kwargs.get("uri_connection")) Try / catch
try:
client = CopilotClient(mode="empty")
except ValueError as e:
if "requires base_directory" in str(e):
client = CopilotClient(mode="empty", base_directory=default_tenant_dir()) Prevention
- 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
When it happens
Trigger: 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__.
Common situations: 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.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- CopilotClient is in mode='empty' but create_session was…
- session_fs.initial_working_directory is required
- session_fs.session_state_path is required
- session_fs.conventions must be either 'posix' or 'windows'
- Invalid . Expected 'inprocess', 'stdio', or unset.
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/4b91b8fc43062f0a.
Report an issue: GitHub.
Appendix: source
Thrown at python/copilot/_mode.py:354
if manage_schedule_enabled is not None:
patch["manageScheduleEnabled"] = manage_schedule_enabled
if included_builtin_skills is not None:
patch["includedBuiltinSkills"] = included_builtin_skills
return patch or None
def _require_storage_for_empty_mode(
*,
mode: CopilotClientMode | None,
base_directory: str | None,
session_fs_set: bool,
is_uri_connection: bool,
) -> None:
if mode != "empty":
return
if base_directory or session_fs_set or is_uri_connection:
return
raise ValueError(
"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."
)
def _require_available_tools_for_empty_mode(
mode: CopilotClientMode | None,
available_tools: list[str] | None,
) -> None:
if mode == "empty" and available_tools is None:
raise ValueError(
"CopilotClient is in mode='empty' but create_session was called "
"without available_tools. Empty mode requires every session to "
"explicitly opt into the tools it wants — e.g. "
"ToolSet().add_builtin(BUILTIN_TOOLS_ISOLATED)."
)
View on GitHub (pinned to cd8cf15dc3)