Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when require('cron-parser') > Cannot assign to read only property 'toString' of object '#<CronDate>' #12755

Open
Meltcap opened this issue Jan 21, 2025 · 5 comments
Labels
in linear Issue or PR has been created in Linear for internal review

Comments

@Meltcap
Copy link

Meltcap commented Jan 21, 2025

Bug Description

Get the error Cannot assign to read only property 'toString' of object '#<CronDate>' because of this line: const cronParser = require('cron-parser')

This worked fine in commit ac2f647. But broke when updating to 565c7b8.

To Reproduce

The workflow below reproduces the error. I did add the environment-variable NODE_FUNCTION_ALLOW_EXTERNAL=cheerio,cron-parser in my Render-environment.

{
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "id": "762eea15-d696-4220-b387-edbfa01736c6",
      "name": "When clicking ‘Test workflow’"
    },
    {
      "parameters": {
        "jsCode": "const cronParser = require('cron-parser')\n\n// Add debug flag at the top\nconst DEBUG = true\nconst SCRAPE_WINDOW_MINUTES = 15  // Window size in minutes\n\n// Add debug logging helper\nfunction debugLog(label, data) {\n    if (DEBUG) {\n        console.log(`\\n=== ${label} ===\\n`, data)\n    }\n}\n\n// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n  const cronExpressions = item.json.notification_schedules\n    ?.filter(schedule => schedule) // Filter out null/undefined\n    .flatMap(schedule => schedule.split('|')) // Split expressions with pipe and flatten\n\n  const lastScrape = item.json.last_scrape // Last moment the site has been checked/scraped\n    \n  debugLog(`Processing Cron Expressions for ${item.json.url}`, cronExpressions)\n    \n  let shouldRun = false\n  if (cronExpressions?.length) {\n    // Create dates in Amsterdam timezone\n    const amsterdamTz = { timeZone: 'Europe/Amsterdam' }\n    const now = new Date(new Date().toLocaleString('en-US', amsterdamTz))\n    const windowEndTime = new Date(now.getTime() + SCRAPE_WINDOW_MINUTES * 60 * 1000)\n    \n    debugLog('Time Window', {\n      now: now.toLocaleString('en-NL'),\n      windowEndTime: windowEndTime.toLocaleString('en-NL')\n    })\n\n    // Check if last scrape falls within the current window\n    if (lastScrape) {\n      const lastScrapeDate = new Date(lastScrape)\n      debugLog('Checking if last scrape falls within the current window', {\n        lastScrape: lastScrapeDate.toLocaleString('en-NL'),\n        windowStart: now.toLocaleString('en-NL'),\n        windowEnd: windowEndTime.toLocaleString('en-NL')\n      })\n      if (lastScrapeDate >= now && lastScrapeDate <= windowEndTime) {\n        debugLog('Skip due to scrape already scheduled in window', {\n          lastScrape: lastScrapeDate.toLocaleString('en-NL')\n        })\n        continue\n      }\n    }\n\n    for (const expression of cronExpressions) {\n      try {\n        const interval = cronParser.parseExpression(expression.trim())\n        const nextRun = interval.next().toDate()\n        \n        // Calculate time difference in minutes\n        const timeDiffMinutes = (nextRun - now) / (1000 * 60)\n        \n        debugLog('Checking Expression', {\n          expression,\n          nextRun: nextRun.toLocaleString('en-NL'),\n          minutesUntilNextRun: timeDiffMinutes,\n          willRunSoon: timeDiffMinutes <= SCRAPE_WINDOW_MINUTES && timeDiffMinutes > 0\n        })\n        \n        if (timeDiffMinutes <= SCRAPE_WINDOW_MINUTES && timeDiffMinutes > 0) {\n          shouldRun = true\n          break\n        }\n      } catch (error) {\n        debugLog('Invalid Cron Expression', {\n          expression,\n          error: error.message\n        })\n      }\n    }\n  }\n  \n  debugLog('Final Result', {\n    shouldRun,\n    itemId: item.json.url || 'unknown'\n  })\n  \n  item.json.shouldRun = shouldRun\n}\n\nreturn $input.all();"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        180,
        0
      ],
      "id": "ac8141e0-141a-4fe2-b3a0-ffe6c9adb681",
      "name": "Code"
    }
  ],
  "connections": {
    "When clicking ‘Test workflow’": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {
    "When clicking ‘Test workflow’": [
      {
        "last_scrape": "2025-01-21T12:01:02.000Z",
        "notification_schedules": [
          "30 8,11,16 * * *"
        ]
      },
      {
        "last_scrape": "2025-01-21T13:31:11.117Z",
        "notification_schedules": [
          "30 8,11,16 * * *"
        ]
      }
    ]
  },
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "fe6b87277380f5fe69eb55d95c4c4c4464d399f0257fd967ba55444232063908"
  }
}

Expected behavior

Give no error when I run const cronParser = require('cron-parser')

Operating System

Render webservice

n8n Version

1.75.0

Node.js Version

22.10.0

Database

SQLite (default)

Execution mode

main (default)

@Joffcom
Copy link
Member

Joffcom commented Jan 21, 2025

Hey @Meltcap,

We have created an internal ticket to look into this which we will be tracking as "N8N-8192"

@Joffcom Joffcom added the in linear Issue or PR has been created in Linear for internal review label Jan 21, 2025
@Joffcom
Copy link
Member

Joffcom commented Jan 21, 2025

Hey @Meltcap,

I have managed to reproduce this on 1.75.1 which would suggest the 2 commits you have found could be unrelated as neither of them are in that version. Are you sure you are looking at the correct commit versions?

Commits aside... This is with the team to be looked into.

@Meltcap
Copy link
Author

Meltcap commented Jan 21, 2025

As you can see in the screenshot, I've just rolled back to ac2f647 and that fixes the problem. Maybe I put in the wrong version number?

Image

@Joffcom
Copy link
Member

Joffcom commented Jan 21, 2025

Hey @Meltcap,

I think I have worked out what the problem could be, I am just waiting for my local instance to update but we recently a few hours ago set N8N_RUNNERS_ENABLED to true as the default option which has been set on my personal instance for a while.

If you set N8N_RUNNERS_ENABLED to false it should start working on the latest version.

@tomi
Copy link
Contributor

tomi commented Jan 22, 2025

Hi @Meltcap,

Thank you for bringing this into our attention! The reason why are seeing this is like @Joffcom explained. We enabled Task Runners by default recently. Task Runner has better performance and is more secure compared to the old way of execution Code node code. Unfortunately certain JS libraries are not compatible with the runtime hardening we are doing. We are looking into this and figuring how we can still keep supporting libraries like cron-parser with Task Runner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in linear Issue or PR has been created in Linear for internal review
Projects
None yet
Development

No branches or pull requests

3 participants