langchain-ai/deepagents · error · ValueError
Workspace policy and fingerprint must be configured…
Error message
Workspace policy and fingerprint must be configured together.
What it means
`set_workspace` accepts an optional workspace policy `config` and its `config_fingerprint`. The two are a matched pair: the fingerprint attests to the exact policy being bound, so providing exactly one of them is ambiguous and raises this ValueError. Both or neither must be supplied.
Solutions
- Pass both arguments together: `set_workspace(cwd, config=policy, config_fingerprint=fingerprint)`.
- If you have no policy, call `set_workspace(cwd)` with neither argument.
- Compute the fingerprint from the same policy object you pass (e.g. a stable hash of the serialized config) so they cannot diverge.
- Audit call sites: if one of the two values can be None while the other is set, normalize them at the source before calling.
Example fix
// before
agent.set_workspace("/project", config=policy) # ValueError
// after
agent.set_workspace("/project", config=policy, config_fingerprint=fingerprint) Defensive patterns
Strategy: validation
Validate before calling
if (config is None) != (config_fingerprint is None):
raise ValueError("Pass both config and config_fingerprint to set_workspace, or neither")
agent.set_workspace(cwd, config=config, config_fingerprint=config_fingerprint) Try / catch
try:
agent.set_workspace(cwd, config=policy, config_fingerprint=fingerprint)
except ValueError as exc:
if "configured together" in str(exc):
logging.error("Workspace policy and fingerprint must both be set or both omitted")
else:
raise Prevention
- Derive the fingerprint from the same policy object you pass, in one helper function.
- Never pass the fingerprint through a variable that can independently be None.
- Wrap policy binding in a single utility so the pair is always supplied together.
When it happens
Trigger: Calling `agent.set_workspace(cwd, config=policy)` without `config_fingerprint=...`, or `agent.set_workspace(cwd, config_fingerprint="...")` without `config`, with the other argument left as None.
Common situations: Adding the fingerprint parameter to an existing call and forgetting the policy (or vice versa); a refactor passing the fingerprint through a variable that is sometimes None while the config is always set; copying a call example that only showed one argument.
Related errors
- allow_fs_tools must be None or a non-empty list
- allow_list must not be empty; disable shell access instead
- assistant id must be 1-128 characters and contain only…
- At least one async subagent must be specified
- Duplicate async subagent names
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/6f0f0f863ce36c76.
Report an issue: GitHub.
Appendix: source
Thrown at libs/code/deepagents_code/client/remote_client.py:848
workspace = cast("dict[str, Any]", response["workspace"])
self._workspaces[thread_id] = workspace
return workspace
def set_workspace(
self,
cwd: str,
config: Mapping[str, Any] | None = None,
*,
config_fingerprint: str | None = None,
) -> None:
"""Configure the explicit workspace used when binding threads.
Raises:
ValueError: If only one policy field is provided.
"""
if (config is None) != (config_fingerprint is None):
msg = "Workspace policy and fingerprint must be configured together."
raise ValueError(msg)
self._workspace_cwd = cwd
self._workspace_config = dict(config) if config is not None else None
self._workspace_config_fingerprint = config_fingerprint
self._workspaces.clear()
async def aensure_thread(self, config: dict[str, Any]) -> None:
"""Ensure the remote thread record exists before mutating state.
In the LangGraph dev server, checkpoint persistence and HTTP thread
registration are separate. After a server restart, a thread may still
have checkpointed state on disk while `POST /threads/{id}/state`
returns 404 because the server has not yet materialized that thread in
its live store.
This method performs the idempotent HTTP-side registration with
`if_exists='do_nothing'` so callers that recovered state from
persistence can safely follow up with `aupdate_state`.
View on GitHub (pinned to a1af029e6e)