Hmbown/CodeWhale · error · anyhow::Error
workspace scope requires a workspace id
Error message
workspace scope requires a workspace id
What it means
Native memory's remember() writes a note to a per-scope Markdown file; the Workspace scope needs a workspace id to compute its path, and None is rejected immediately after normalize_note() validated the text. This is a caller-contract violation, not an environmental failure — the note is treated as data, never instructions.
Source
Thrown at crates/tui/src/native_memory.rs:210
fs::write(&target, content)?;
self.reindex_file(&target)?;
Ok(true)
})
}
/// Append a reviewed note to the selected Markdown source and refresh its
/// index. The note is treated as data, never as an instruction.
pub fn remember(
&self,
scope: MemoryScope,
workspace_id: Option<&str>,
note: &str,
) -> Result<MemoryHit> {
let note = normalize_note(note)?;
let path = match scope {
MemoryScope::Global => self.global_path(),
MemoryScope::Workspace => self.workspace_path(
workspace_id.ok_or_else(|| anyhow!("workspace scope requires a workspace id"))?,
)?,
};
self.with_write_lock(|| {
ensure_memory_file(&path)?;
let before = fs::read_to_string(&path).unwrap_or_default();
let line_start = before.lines().count().saturating_add(2);
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(&path)
.with_context(|| format!("open memory source {}", path.display()))?;
if !before.is_empty() && !before.ends_with('\n') {
writeln!(file)?;
}
writeln!(file, "\n- {note}")?;
file.sync_data()?;
self.reindex_file(&path)?;
let line_end = line_start;View on GitHub (pinned to 8880682c63)
Solutions
- Pass the session's workspace id whenever scope is Workspace
- When no workspace context exists, record with MemoryScope::Global instead
- Fix the caller to resolve the workspace id before choosing the scope
Example fix
// before
memory.remember(MemoryScope::Workspace, None, note)?;
// after
let scope = match workspace_id {
Some(_) => MemoryScope::Workspace,
None => MemoryScope::Global,
};
memory.remember(scope, workspace_id, note)?; Defensive patterns
Strategy: validation
Validate before calling
```rust
// Derive the scope from the id you actually have, before calling remember():
let scope = match workspace_id {
Some(_) => MemoryScope::Workspace,
None => MemoryScope::Global,
};
memory.remember(scope, workspace_id, note)?;
``` Type guard
```rust
fn requires_workspace_id(scope: MemoryScope) -> bool {
matches!(scope, MemoryScope::Workspace)
}
``` Prevention
- Resolve the workspace id from the session before accepting a user-selected scope
- Default the scope to Global when no workspace is active instead of erroring
When it happens
Trigger: Calling remember(MemoryScope::Workspace, None, note): the remember tool invoked with scope=workspace while the session had no workspace context or the caller dropped the workspace id.
Common situations: Sessions started outside any workspace directory; tool wiring forwarding the scope but not the id; scripted calls hardcoding scope=workspace.
Related errors
- ${name} is unavailable in Workflow scripts: runs must be det
- new Date()/Date() is unavailable in Workflow scripts: runs m
- task(): expected an options object
- workspace memory requires a git repository with an origin
- plugin registry workspace does not match MCP pool workspace
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/adf7689a910fb882.
Report an issue: GitHub.