openclaw - ✅(Solved) Fix [BUG] CronToolSchema: job property has empty properties — causes GPT-5.4 to send job: {} [1 pull requests, 1 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#55035Fetched 2026-04-08 01:33:23
View on GitHub
Comments
0
Participants
1
Timeline
27
Reactions
0
Participants
Timeline (top)
referenced ×23closed ×1cross-referenced ×1locked ×1

When using GPT-5.4 (via OpenRouter) with OpenClaw 2026.3.24 (cff6dc9), asking the agent to create a cron job results in an infinite retry loop. The agent sends job: {} on every cron.add call, and the gateway rejects it with INVALID_REQUEST.

Root Cause

In the bundled file dist/pi-embedded-BaSvmUpW.js, the CronToolSchema defines the job parameter as:

job: Type.Optional(Type.Object({}, { additionalProperties: true }))

This produces the following JSON Schema fragment:

{
  "job": {
    "type": "object",
    "properties": {},
    "additionalProperties": true
  }
}

Because properties is an empty object, GPT-5.4 strictly follows the schema and sends job: {}. The gateway then rejects this as invalid, the agent retries, and the loop continues (aseq reaching 300+).

Fix Action

Fix / Workaround

job: Type.Optional(Type.Object({
  name: Type.Optional(Type.String()),
  schedule: Type.Optional(Type.Object({
    kind: Type.String(),           // "every" | "cron"
    everyMs: Type.Optional(Type.Number()),
    cron: Type.Optional(Type.String()),
  })),
  payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   paylol(Type.String()),
  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Typet-  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal( with the explicit schema above.
- After patching, GPT-5.4 correctly sends fully-populated `job` objects:

PR fix notes

PR #55043: fix(cron-tool): add typed properties to job/patch schemas

Description (problem / solution / changelog)

Problem

CronToolSchema defines job and patch as Type.Object({}, { additionalProperties: true }), producing "properties": {}. Strict models (GPT-5.4) follow the schema literally and send job: {}, which the gateway rejects.

Closes #55035

Solution

Spell out the sub-properties for job, patch, and their nested objects (schedule, payload, delivery, failureAlert) so that models know which fields to send.

What does NOT change

  • Runtime validation (handled by normalizeCronJob*)
  • additionalProperties: true (preserved everywhere)
  • Flattened schema with per-action parameters

Tests

cron-tool.schema.test.ts: 6 regression tests that assert the exact field list for job, patch, and nested objects. Any accidental field removal breaks the test.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/tools/cron-tool.schema.test.ts (added, +171/-0)
  • src/agents/tools/cron-tool.test.ts (modified, +279/-0)
  • src/agents/tools/cron-tool.ts (modified, +239/-44)
  • src/cron/normalize.test.ts (modified, +308/-0)
  • src/cron/normalize.ts (modified, +120/-26)
  • src/cron/service.jobs.test.ts (modified, +119/-0)
  • src/cron/service/jobs.ts (modified, +10/-0)
  • src/cron/types.ts (modified, +3/-1)
  • src/gateway/protocol/schema/cron.ts (modified, +10/-3)

Code Example

job: Type.Optional(Type.Object({}, { additionalProperties: true }))

---

{
  "job": {
    "type": "object",
    "properties": {},
    "additionalProperties": true
  }
}

---

job: Type.Optional(Type.Object({
  name: Type.Optional(Type.String()),
  schedule: Type.Optional(Type.Object({
    kind: Type.String(),           // "every" | "cron"
    everyMs: Type.Optional(Type.Number()),
    cron: Type.Optional(Type.String()),
  })),
  payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   paylol(Type.String()),
  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Typet-  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal( with the explicit schema above.
- After patching, GPT-5.4 correctly sends fully-populated `job` objects:
RAW_BUFFERClick to expand / collapse

Summary

When using GPT-5.4 (via OpenRouter) with OpenClaw 2026.3.24 (cff6dc9), asking the agent to create a cron job results in an infinite retry loop. The agent sends job: {} on every cron.add call, and the gateway rejects it with INVALID_REQUEST.

Root Cause

In the bundled file dist/pi-embedded-BaSvmUpW.js, the CronToolSchema defines the job parameter as:

job: Type.Optional(Type.Object({}, { additionalProperties: true }))

This produces the following JSON Schema fragment:

{
  "job": {
    "type": "object",
    "properties": {},
    "additionalProperties": true
  }
}

Because properties is an empty object, GPT-5.4 strictly follows the schema and sends job: {}. The gateway then rejects this as invalid, the agent retries, and the loop continues (aseq reaching 300+).

Reproduction

  1. Install [email protected]
  2. Ask the agent: "Create a cron job that says hello every 3 minutes"
  3. Observe session logs — every cron.add call sends job: {}

Expected Behavior

The job property should have explicit sub-properties so the model knows what fields to populate. For example:

job: Type.Optional(Type.Object({
  name: Type.Optional(Type.String()),
  schedule: Type.Optional(Type.Object({
    kind: Type.String(),           // "every" | "cron"
    everyMs: Type.Optional(Type.Number()),
    cron: Type.Optional(Type.String()),
  })),
  payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   payload:   paylol(Type.String()),
  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Typet-  wakeMode: Type.Op  onal(Type.Strin  wakeMode: Type.Op  onal( with the explicit schema above.
- After patching, GPT-5.4 correctly sends fully-populated `job` objects:

```json
{
  "job": {
    "name": "hello-cron",
    "schedule": { "kind": "every", "everyMs": 180000 },
    "sessionTarget": "main",
    "payload": { "kind": "systemEvent", "text": "Hello world" },
    "wakeMode": "reuse-or-create",
    "delivery": "enqueue",
    "enabled": true
  }
}

Environment

  • OpenClaw: 2026.3.24 (cff6dc9)
  • Model: openrouter/openai/gpt-5.4
  • OS: macOS (also tested in Docker/Node 22 Alpine)
  • Node: 22.x

extent analysis

Fix Plan

To resolve the infinite retry loop issue, we need to update the CronToolSchema to include explicit sub-properties for the job parameter.

Here are the steps:

  • Update the CronToolSchema definition to include the required sub-properties:
job: Type.Optional(Type.Object({
  name: Type.Optional(Type.String()),
  schedule: Type.Optional(Type.Object({
    kind: Type.String(),           // "every" | "cron"
    everyMs: Type.Optional(Type.Number()),
    cron: Type.Optional(Type.String()),
  })),
  payload: Type.Optional(Type.String()),
  wakeMode: Type.Optional(Type.String()),
  delivery: Type.Optional(Type.String()),
  enabled: Type.Optional(Type.Boolean())
}))
  • Ensure that the updated schema is correctly bundled and deployed.
  • Verify that the job object is being sent with the expected sub-properties.

Verification

To verify that the fix worked, you can:

  • Check the session logs to ensure that the job object is being sent with the expected sub-properties.
  • Test creating a cron job using the agent and verify that it is successfully created without entering an infinite retry loop.

Extra Tips

  • Make sure to update the CronToolSchema definition in the correct location, which is in the dist/pi-embedded-BaSvmUpW.js file.
  • If you are using a version control system, ensure that the updated schema is committed and deployed to the production environment.
  • Consider adding additional logging or monitoring to detect and prevent similar issues in the future.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [BUG] CronToolSchema: job property has empty properties — causes GPT-5.4 to send job: {} [1 pull requests, 1 participants]