Skip to content

fix(daemon): send log_message to stderr to avoid polluting command substitution - #19

Open
dmitrytkachuk wants to merge 1 commit into
aniketkarne:mainfrom
dmitrytkachuk:fix/log-message-stdout-pollutes-command-substitution
Open

fix(daemon): send log_message to stderr to avoid polluting command substitution#19
dmitrytkachuk wants to merge 1 commit into
aniketkarne:mainfrom
dmitrytkachuk:fix/log-message-stdout-pollutes-command-substitution

Conversation

@dmitrytkachuk

Copy link
Copy Markdown

Summary

log_message writes to stdout via tee. Inside calculate_sleep_duration() it logs Time remaining: N minutes, but the caller captures that function's stdout with sleep_duration=$(calculate_sleep_duration). So sleep_duration becomes a two-line string (log text + number), and $((sleep_duration / 60)) crashes with a bash syntax error every loop iteration.

Under systemd with Restart=always, the daemon crash-loops and renewals never fire. My instance restarted 500+ times overnight.

Repro

Observed in journal:

claude-auto-renew-daemon.sh: line 471: [2026-04-19 01:00:53] Time remaining: 59 minutes
600: syntax error: operand expected (error token is "[2026-04-19 01:00:53] Time remaining: 59 minutes
600")
claude-auto-renew.service: Main process exited, code=exited, status=1/FAILURE

The bug was latent until ccusage started returning a value — the "ccusage returned nothing" fallback branch does not call log_message, so earlier installs worked by accident.

Fix

Redirect log_message output to stderr (tee -a "$LOG_FILE" >&2). systemd/journal capture both streams, so user-visible log output is unchanged. Verified no callsite uses $(log_message ...), so this is safe globally.

Test plan

  • Ran patched daemon under systemctl --user; observed 7+ successful 10-minute check cycles with no restarts, no syntax errors, and Time remaining correctly decreasing as ccusage data ticks down.

…bstitution

calculate_sleep_duration() emits a "Time remaining: N minutes" log via
log_message and returns the sleep interval on stdout. The caller captures
that stdout with $(calculate_sleep_duration), so before this change the
captured value was the multi-line string:

    [2026-04-19 01:00:53] Time remaining: 59 minutes
    600

Then `$((sleep_duration / 60))` crashed with:

    line 471: [2026-04-19 ...] Time remaining: 59 minutes
    600: syntax error: operand expected (error token is "...")

which killed the daemon every loop iteration. Under systemd with
Restart=always, the daemon crash-looped ~500+ times overnight and renewal
checks never ran.

The bug was dormant previously because the only log_message call inside
calculate_sleep_duration sits on the ccusage branch; when ccusage
returned nothing, the fallback branch (no log_message) was taken.

Fix: redirect log_message's echo|tee to stderr. journal/terminal output
is unchanged (systemd captures both streams), and stdout capture by
callers is no longer polluted. Verified that no callsite captures
log_message output via command substitution, so this is safe globally.
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.

2 participants