Hmbown/CodeWhale · error

AutomationEditorInvalidWorkspace

Error message

AutomationEditorInvalidWorkspace

What it means

AutomationEditor::save validates that the workspace field is non-empty and that the resolved path (absolute, or joined with workspace_root) is an existing directory; otherwise it throws the localized AutomationEditorInvalidWorkspace message. The editor cannot persist an automation whose cwd points at nothing usable.

Solutions

  1. Enter an existing directory path in the workspace field (or leave a valid default) before saving.
  2. Verify the directory still exists on disk; recreate it if it was deleted.
  3. Use an absolute path, or ensure the relative path resolves under workspace_root.

Example fix

// before
path: "~/projs"

// after (must exist and be a directory)
path: "/home/user/projs"
Defensive patterns

Strategy: validation

Validate before calling

let p = editor.workspace.value.trim();
let path = if Path::new(p).is_absolute() { PathBuf::from(p) } else { editor.workspace_root.join(p) };
let ok = !p.is_empty() && path.is_dir();

Try / catch

match editor.save() {
    Err(e) if e.to_string().contains("workspace") => show_workspace_error_and_refocus_field(),
    other => other?,
}

Prevention

When it happens

Trigger: Saving the automation editor while workspace.value.trim() is empty, or the entered path (after joining with workspace_root when relative) is not a directory (missing, deleted, or a file).

Common situations: User cleared the workspace field; typed a typo'd path; referenced a directory that was deleted or renamed after the editor opened; entered a relative path that doesn't resolve under workspace_root.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/df341730d73872f7. 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 73e0f67d83)