Skip to content

Invalid systemd OnCalendar syntax that causes timers to fail #3

@jondoran

Description

@jondoran

Description

When scheduling jobs with cron expressions, the plugin generates invalid systemd OnCalendar syntax that causes timers to fail with "Failed to parse calendar specification".

Environment

  • opencode-scheduler: v1.1.0
  • opencode: v1.1.36
  • systemd: 255 (255.4-1ubuntu8.11)
  • OS: Linux (Ubuntu)

Steps to Reproduce

  1. Run: Schedule a job every minute to test
  2. Check generated timer: cat ~/.config/systemd/user/opencode-job-test.timer
  3. Attempt to start: systemctl --user daemon-reload && systemctl --user start opencode-job-test.timer
  4. Check status: systemctl --user status opencode-job-test.timer

Expected Behavior

Timer should have valid OnCalendar syntax and start successfully.

Actual Behavior

Generated timer has invalid syntax with spurious leading asterisk:

OnCalendar=* *-*-* *:00:00
OnCalendar=* *-*-* *:01:00
...
OnCalendar=* *-*-* *:59:00

Error from systemd:

Failed to parse calendar specification, ignoring: * *-*-* *:00:00
Timer unit lacks value setting. Refusing.

Root Cause

The cron-to-systemd conversion logic adds a spurious leading asterisk that systemd cannot parse.

Invalid (current output): OnCalendar=* *-*-* *:00:00
Valid syntax: OnCalendar=*-*-* *:00:00

According to systemd.timer(5) documentation, the correct format for OnCalendar is:

DayOfWeek Year-Month-Day Hour:Minute:Second

Valid examples:

OnCalendar=*-*-* 09:00:00              # Every day at 9am
OnCalendar=Mon-Fri 09:00:00            # Weekdays at 9am
OnCalendar=*-*-* *:*:00                # Every minute
OnCalendar=*-*-* *:0/5:00              # Every 5 minutes

The leading asterisk is not part of the format and causes the parser to fail.

Validation

This can be verified using systemd's built-in validation:

# Invalid (fails):
systemd-analyze calendar "* *-*-* *:00:00"
# Output: Failed to parse calendar specification

# Valid (succeeds):
systemd-analyze calendar "*-*-* *:00:00"
# Output: Original form: *-*-* *:00:00, Normalized form: *-*-* *:00:00, Next elapse: [timestamp]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions