openclaw - ✅(Solved) Fix [Bug]: `openclaw cron list` crashes with TypeError: value.padEnd is not a function [2 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#70128Fetched 2026-04-23 07:28:53
View on GitHub
Comments
2
Participants
3
Timeline
9
Reactions
0
Author
Timeline (top)
commented ×2cross-referenced ×2labeled ×2referenced ×2

openclaw cron list crashes with an unhandled TypeError when formatting cron entries, making the interactive CLI listing unusable — only --json works.

Root Cause

Root cause, in cron-cli-*.js:

Fix Action

Fix / Workaround

Affected: any deployment running openclaw cron list where at least one cron entry has a non-string formatted field. Severity: Low — the --json variant works as a workaround, but the default interactive command is broken. Frequency: Consistent when triggering conditions are present. Consequence: Operators cannot inspect cron entries interactively without falling back to --json or raw JSON parsing.

PR fix notes

PR #70155: fix: handle non-string values in cron list pad helper (fixes #70128)

Description (problem / solution / changelog)

Summary

Fixes #70128

Root Cause

The pad helper in cron-cli-*.js called value.padEnd(width) directly, which throws a TypeError when value is null, undefined, or a non-string type.

Fix

Wrapped value with String() and nullish coalescing fallback:

Before: const pad = (value, width) => value.padEnd(width);

After: const pad = (value, width) => String(value ?? "").padEnd(width);

Testing

  • openclaw cron list no longer crashes when a cron entry has a missing/non-string field
  • openclaw cron list --json continues to work as before

Changed files

  • src/cli/cron-cli/shared.ts (modified, +1/-1)

PR #70183: fix(cron): coerce pad value so cron list survives non-string job id

Description (problem / solution / changelog)

Summary

  • Problem: openclaw cron list crashes with TypeError: value.padEnd is not a function whenever a cron entry surfaces job.id as a non-string (numeric or undefined, from older-schema or corrupted store data). --json output is unaffected, which is how the reporter routed around it.
  • Why it matters: the default interactive list command is unusable for affected operators. #70128 confirmed on 2026.4.15 and 2026.4.21 (same unchanged pad implementation in both shipped dists).
  • What changed: pad() in src/cli/cron-cli/shared.ts now widens its parameter type to string | number | null | undefined and coerces non-string primitives via a typeof-guarded String() so padEnd always runs on a string.
  • What did NOT change (scope boundary): no changes to truncate(), table headers, --json output, or the store/migration path. CronJob.id schema type stays string; only the render-side helper is defensive.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #70128
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: pad() was typed (value: string, width: number) and call site pad(job.id, CRON_ID_PAD) at src/cli/cron-cli/shared.ts:278 passes job.id unguarded. CronJob.id is typed string at compile time, but older-schema or corrupted entries can surface it as numeric/undefined at runtime. TypeScript does not enforce this for external data, so value.padEnd(width) throws on the first non-string row.
  • Missing detection / guardrail: no regression test covered cron entries with non-string job.id shapes.
  • Contributing context (if known): #70128 triage by @rafiki270 root-caused to this helper and confirmed the minimal fix; call-site audit showed all other pad() calls already go through string literals, truncate(), or ?? "-" fallbacks, so job.id at :278 is the only unguarded external field.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/cli/cron-cli/shared.test.ts
  • Scenario the test should lock in: printCronList must not throw when job.id is numeric or undefined, and must still emit the table row.
  • Why this is the smallest reliable guardrail: the crash is in the shared render helper, so a focused printCronList test catches it at the exact seam without needing full gateway/store wiring.
  • Existing test that already covers this (if any): none.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • openclaw cron list no longer crashes when a cron entry has a non-string job.id. Numeric ids render stringified (e.g. 42 shows as 42); undefined/null ids render as blank padding so the other columns still line up.

Diagram (if applicable)

N/A

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Linux x64
  • Runtime/container: Node 22.22.2, pnpm 10.33.0, local repo checkout
  • Model/provider: N/A
  • Integration/channel (if any): N/A
  • Relevant config (redacted): N/A

Steps

  1. Stash the pad() change and keep the two new tests in place.
  2. Run pnpm test src/cli/cron-cli/shared.test.ts.
  3. Observe both new cases fail with the exact reported TypeError.
  4. Pop the stash, rerun.
  5. Observe all 22 tests green.

Expected

  • Pre-fix: 2 new tests fail with TypeError: value.padEnd is not a function (numeric id) and TypeError: Cannot read properties of undefined (reading 'padEnd') (undefined id).
  • Post-fix: all 22 tests pass.

Actual

Stash-bisect output:

Pre-fix:

Tests  2 failed | 20 passed (22)
FAIL  src/cli/cron-cli/shared.test.ts > printCronList > handles job with non-string id (#70128)
AssertionError: expected [Function] to not throw an error but 'TypeError: value.padEnd is not a func…' was thrown
FAIL  src/cli/cron-cli/shared.test.ts > printCronList > handles job with undefined id (#70128)
AssertionError: expected [Function] to not throw an error but 'TypeError: Cannot read properties of …' was thrown

Post-fix:

Test Files  1 passed (1)
Tests  22 passed (22)

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
    • Reproduced the .padEnd crash locally via stash-bisect against the new regression tests.
    • Confirmed all 22 src/cli/cron-cli/shared.test.ts cases pass post-fix.
    • Ran pnpm check:changed (conflict markers, typecheck core, typecheck core tests, lint core, runtime import cycles, webhook body guard, pairing store/account guards, tests changed) — all green.
  • Edge cases checked:
    • Numeric job.id renders as stringified digits (42 in the output).
    • Undefined/null job.id renders as blank padding, row still emits.
    • String job.id keeps existing .padEnd behavior (20 original tests still green).
  • What you did not verify:
    • Live openclaw cron list against a real gateway with an actually-corrupted store entry; the crash path is a pure render helper so the unit test is the correct seam.
    • Full pnpm check / pnpm test sweep — pre-commit oxfmt hit EAGAIN on this container (process spawn limit across tinypool workers); check:changed covered the touched surface and format diff was visually verified against existing file conventions.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: widening pad()'s parameter type could mask a genuine non-string leak upstream (e.g. a broken store migration) that would be better fixed at the schema layer.
    • Mitigation: the helper is the last-line render defense; the store and gateway contracts still type CronJob.id as string, so this change only affects what the operator sees when corruption already exists. The typeof guard preserves strict-string behavior for well-formed entries, and the fix is isolated enough to revert cleanly if a better upstream guard lands.

AI-assisted

  • Mark as AI-assisted: yes, authored by truffle (github.com/truffle-dev).
  • Degree of testing: fully tested — stash-bisect repro + check:changed green + 22/22 targeted tests.
  • Prompts / session logs: available on request.
  • Confirm you understand what the code does: yes.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/cli/cron-cli/shared.test.ts (modified, +28/-0)
  • src/cli/cron-cli/shared.ts (modified, +2/-1)

Code Example

Root cause, in cron-cli-*.js:

  const pad = (value, width) => value.padEnd(width);

padEnd is a String.prototype method; passing non-string values throws the TypeError above.

Verified in both 2026.4.15 and 2026.4.21 by inspecting the published dist:
- /opt/homebrew/lib/node_modules/openclaw/dist/cron-cli-*.js (installed 4.15)
- package/dist/cron-cli-*.js (4.21 tarball from npm)
Both contain the same unchanged pad implementation.
RAW_BUFFERClick to expand / collapse

Bug type

Crash (process/app exits or hangs)

Beta release blocker

No

Summary

openclaw cron list crashes with an unhandled TypeError when formatting cron entries, making the interactive CLI listing unusable — only --json works.

Steps to reproduce

  1. Install OpenClaw 2026.4.15 (or any recent version).
  2. Configure one or more cron entries where a formatted field may not be a string (e.g., missing agent id or model value).
  3. Run openclaw cron list.
  4. Observe unhandled TypeError and CLI exit.

Expected behavior

The command should render a human-readable table listing all configured cron entries, consistent with the behavior of openclaw cron list --json which does work correctly.

Actual behavior

The command crashes with:

TypeError: value.padEnd is not a function at pad (.../cron-cli-*.js)

The pad helper calls value.padEnd(width) directly, which throws when value is not a string (undefined, null, number).

OpenClaw version

2026.4.15 (verified persists in 2026.4.21 — the pad implementation is identical in both versions)

Operating system

macOS 15.4

Install method

npm global

Model

Not applicable — CLI crash path, no model involved.

Provider / routing chain

Not applicable — CLI crash path.

Additional provider/model setup details

NOT_ENOUGH_INFO

Logs, screenshots, and evidence

Root cause, in cron-cli-*.js:

  const pad = (value, width) => value.padEnd(width);

padEnd is a String.prototype method; passing non-string values throws the TypeError above.

Verified in both 2026.4.15 and 2026.4.21 by inspecting the published dist:
- /opt/homebrew/lib/node_modules/openclaw/dist/cron-cli-*.js (installed 4.15)
- package/dist/cron-cli-*.js (4.21 tarball from npm)
Both contain the same unchanged pad implementation.

Impact and severity

Affected: any deployment running openclaw cron list where at least one cron entry has a non-string formatted field. Severity: Low — the --json variant works as a workaround, but the default interactive command is broken. Frequency: Consistent when triggering conditions are present. Consequence: Operators cannot inspect cron entries interactively without falling back to --json or raw JSON parsing.

Additional information

Proposed fix (one-line change):

const pad = (value, width) => String(value ?? "").padEnd(width);

Happy to submit a PR.

extent analysis

TL;DR

The openclaw cron list command can be fixed by modifying the pad function to handle non-string values by converting them to strings before calling padEnd.

Guidance

  • The root cause of the issue is the pad function not handling non-string values, which can be fixed by converting the value to a string before calling padEnd.
  • To verify the fix, run openclaw cron list with a cron entry that has a non-string formatted field and check that the command no longer crashes.
  • The proposed fix const pad = (value, width) => String(value ?? "").padEnd(width); should be applied to the cron-cli-*.js file.
  • Before applying the fix, make sure to backup the original file to allow for easy reversion if needed.

Example

const pad = (value, width) => String(value ?? "").padEnd(width);

This code snippet shows the proposed fix, which converts the value to a string before calling padEnd, preventing the TypeError.

Notes

The fix assumes that the pad function is the only place where non-string values are being passed to padEnd. If there are other places where this issue could occur, additional fixes may be needed.

Recommendation

Apply the workaround by modifying the pad function as proposed, as it is a simple and effective fix for the issue. This will allow the openclaw cron list command to work correctly even with non-string formatted fields.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The command should render a human-readable table listing all configured cron entries, consistent with the behavior of openclaw cron list --json which does work correctly.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING