Skip to content

fix: handle shell command parsing errors instead of silently failing#132

Merged
jdx merged 3 commits intomainfrom
fix/shell-parsing-error-handling
Jan 19, 2026
Merged

fix: handle shell command parsing errors instead of silently failing#132
jdx merged 3 commits intomainfrom
fix/shell-parsing-error-handling

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Jan 19, 2026

Summary

  • Replace shell_words::split().unwrap_or_default() with proper error handling
  • Log errors when shell command parsing fails instead of silently using empty commands
  • Skip/abort the operation gracefully instead of proceeding with invalid state

This prevents daemons from starting with no command when there's a syntax error in the run field, making debugging much easier.

Test plan

  • Build passes
  • All tests pass
  • Manually test with an invalid command containing unmatched quotes

🤖 Generated with Claude Code


Note

Improves resilience and debuggability when parsing daemon run commands from pitchfork.toml.

  • Replace unwrap_or_default() with explicit shell_words::split error handling in supervisor.rs for retries, boot starts, and cron triggers; log errors and skip runs (retry path marks retries exhausted to avoid loops)
  • web/routes/daemons.rs: on Start, parse command with error handling and return a contextual error block/row (depending on detail/list view) instead of proceeding
  • Ensures daemons never start with empty commands and prevents infinite retry cycles on malformed commands

Written by Cursor Bugbot for commit 0684f45. This will update automatically on new commits. Configure here.

Previously, shell_words::split() errors were silently converted to empty
command vectors via unwrap_or_default(), which could cause daemons to
start with no command instead of failing visibly.

Now parsing errors are logged and the operation is skipped/aborted,
making debugging much easier when commands contain syntax errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Err(e) => {
error!("failed to parse command for cron daemon {}: {}", id, e);
continue;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeated cron trigger errors without state update

Low Severity

When shell_words::split fails in check_cron_schedules, the code logs an error and executes continue without updating daemon state. For cron daemons with Always or Finish retrigger modes, the should_run condition will remain true on subsequent cron triggers, causing repeated error logging on every schedule match. Unlike the retry case, cron triggers are schedule-based (checked every 60 seconds), so impact is lower but the error will recur indefinitely for permanent config errors.

Fix in Cursor Fix in Web

- Mark daemon as exhausted when command parsing fails in retry loop,
  preventing infinite retry attempts every 10 seconds
- Return correct HTML structure based on from_detail context in web route,
  fixing broken table structure when called from list page

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Pass the daemon's current status to upsert_daemon when marking as
exhausted due to command parse failure, instead of using Default
which would overwrite Errored status with Stopped.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@jdx jdx merged commit 95c1a04 into main Jan 19, 2026
4 checks passed
@jdx jdx deleted the fix/shell-parsing-error-handling branch January 19, 2026 03:10
@jdx jdx mentioned this pull request Jan 18, 2026
jdx added a commit that referenced this pull request Jan 19, 2026
## 🤖 New release

* `pitchfork-cli`: 0.3.0 -> 0.3.1

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

## [0.3.1](v0.3.0...v0.3.1) -
2026-01-19

### Added

- implement daemon dependency resolution
([#135](#135))
- add restart command to CLI
([#134](#134))

### Fixed

- restart command preserves daemon dependency configuration
([#142](#142))
- add missing depends field to restart command
([#136](#136))
- set IPC socket permissions to 0600 for security
([#133](#133))
- handle shell command parsing errors instead of silently failing
([#132](#132))

### Other

- reduce unnecessary daemon cloning in loops
([#144](#144))
- use periodic log flushing instead of per-line
([#139](#139))
- refresh only tracked PIDs instead of all processes
([#141](#141))
- cache compiled regex patterns
([#143](#143))

### Security

- add rate limiting to IPC server
([#137](#137))
- canonicalize config paths to prevent symlink exploitation
([#138](#138))
- add centralized daemon ID validation
([#140](#140))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Prepares the 0.3.1 release and updates metadata/documentation
accordingly.
> 
> - **Changelog**: Adds `0.3.1` entry detailing added dependency
resolution, new `restart` command, fixes, performance tweaks, and
security hardening
> - **Version bumps**: Updates `version` to `0.3.1` in `Cargo.toml`,
`Cargo.lock`, `docs/cli/commands.json`, `docs/cli/index.md`, and
`pitchfork.usage.kdl`
> - **Docs regen**: Refreshes CLI docs/spec to reflect the new version
(no behavioral changes in this diff)
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9f9d386. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@jdx jdx mentioned this pull request Jan 19, 2026
jdx added a commit that referenced this pull request Jan 19, 2026
## 🤖 New release

* `pitchfork-cli`: 1.0.0

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

## [1.0.0](https://github.com/jdx/pitchfork/releases/tag/v1.0.0) -
2026-01-19

### Added

- implement daemon dependency resolution
([#135](#135))
- add restart command to CLI
([#134](#134))

### Fixed

- restart command preserves daemon dependency configuration
([#142](#142))
- add missing depends field to restart command
([#136](#136))
- set IPC socket permissions to 0600 for security
([#133](#133))
- handle shell command parsing errors instead of silently failing
([#132](#132))

### Other

- bump version to 1.0.0
([#147](#147))
- release v0.3.1 ([#121](#121))
- reduce unnecessary daemon cloning in loops
([#144](#144))
- use periodic log flushing instead of per-line
([#139](#139))
- refresh only tracked PIDs instead of all processes
([#141](#141))
- cache compiled regex patterns
([#143](#143))

### Security

- add rate limiting to IPC server
([#137](#137))
- canonicalize config paths to prevent symlink exploitation
([#138](#138))
- add centralized daemon ID validation
([#140](#140))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Prepares the 1.0.0 release and updates `CHANGELOG.md` with the
finalized notes.
> 
> - Adds `1.0.0` section: daemon dependency resolution, new CLI
`restart` command, fixes for dependency preservation and shell parsing,
secure IPC socket perms, plus performance/maintenance updates
> - Documents security hardening: IPC rate limiting, config path
canonicalization, centralized daemon ID validation
> - Retains prior `0.3.1` notes for historical context
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
4182984. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant