Hmbown/CodeWhale · error

tr(self.locale, MessageId::AutomationEditorInvalidWorkspace)

Error message

tr(self.locale, MessageId::AutomationEditorInvalidWorkspace)

What it means

Thrown in `AutomationEditor::save` when the workspace field is blank or the resolved path is not an existing directory. The editor resolves the workspace value against the workspace root when it is not absolute, then validates it before saving the automation. The message is the localized `AutomationEditorInvalidWorkspace` string.

Solutions

  1. Enter an absolute path to an existing directory in the workspace field
  2. Create the target directory before saving (mkdir -p the path)
  3. Verify the path exists and is a directory (not a file) from the shell
  4. Reopen the editor after fixing the path so the workspace_root join resolves correctly

Example fix

// before
workspace = "~/project/src"  // points at a file
// after
workspace = "/home/user/projects/src"  // absolute, existing directory
Defensive patterns

Strategy: validation

Validate before calling

let p = if Path::new(&ws).is_absolute() { PathBuf::from(&ws) } else { root.join(&ws) };
if ws.trim().is_empty() || !p.is_dir() { return Err("invalid workspace"); }

Try / catch

match save_result {
    Err(e) if e.to_string().contains("Invalid workspace") => {
        // show the localized message and refocus the workspace field
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `save` with `workspace.value` trimmed-empty, or with a path (joined onto `workspace_root` if relative) that fails `path.is_dir()` — e.g. a typo'd directory, a file path, or a directory that no longer exists.

Common situations: Typing a relative workspace path while running the TUI from a different cwd; moving/renaming the automation's target directory after the editor was opened; leaving the workspace field blank; passing a file instead of a directory.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/b3cb721c5001d32e. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tui/views/automations/editor.rs:648

                .to_string()
        });
        let workspace_changed = old_workspace.as_deref() != Some(self.workspace.value.as_str());
        let mut cwds = self
            .original
            .as_ref()
            .map(|r| r.cwds.clone())
            .unwrap_or_default();
        // Leave old multi-workspace definitions intact; the existing scheduler
        // executes their first workspace. Editing that field keeps the tail.
        if workspace_changed {
            let path = PathBuf::from(self.workspace.value.trim());
            let path = if path.is_absolute() {
                path
            } else {
                self.workspace_root.join(path)
            };
            if self.workspace.value.trim().is_empty() || !path.is_dir() {
                anyhow::bail!(
                    "{}",
                    tr(self.locale, MessageId::AutomationEditorInvalidWorkspace)
                );
            }
            let path = path.canonicalize()?;
            if cwds.is_empty() {
                cwds.push(path);
            } else {
                cwds[0] = path;
            }
        }
        if let Some(original) = &self.original {
            let latest = manager.get_automation(&original.id)?;
            let request = UpdateAutomationRequest {
                name: (self.name.value != original.name).then(|| self.name.value.clone()),
                prompt: (self.prompt.value != original.prompt).then(|| self.prompt.value.clone()),
                rrule: self.schedule_changed.then_some(rrule),
                cwds: workspace_changed.then_some(cwds),

View on GitHub (pinned to 433685b202)