Skip to content

Range node treats null, booleans and empty strings as numbers (null → 0, true → 1, false → 0, "" → 0) #5970

Description

@JMBMdes

Current Behavior

The range node coerces its input with Number(value) and only rejects the result if it is NaN (16-range.js):

var n = Number(value);
if (!isNaN(n)) { ...scale and send... }
else { node.log(RED._("range.errors.notnumber")+": "+value); }

Because of JavaScript's coercion rules, several non-numeric inputs pass that check and get scaled as if they were real readings:

input msg.payload Number(value) range node output (scale 0–100 → 0–1)
null 0 0 — sent as a valid reading
true 1 0.01
false 0 0
"" (empty string) 0 0
" " (whitespace) 0 0
[] 0 0
"abc" NaN dropped + "notnumber" log (correct)
undefined / missing — passed through unchanged

With action "drop if out of range", a null is not dropped whenever 0 is inside the input range. It comes out as a real 0.

Expected Behavior

Only numbers, and strings that actually contain a number, should be scaled. null, booleans, empty or whitespace-only strings and arrays/objects should get the same handling "abc" already gets: not sent, with the existing "notnumber" log line. Or, if you'd rather keep the node forgiving, the behaviour could at least be documented in the node's help text. At the moment the help only says the node scales numeric values.

A possible check, keeping numeric strings working:

function toNumber(v) {
    if (typeof v === "number") return v;
    if (typeof v === "string" && v.trim() !== "") return Number(v);
    return NaN;
}
var n = toNumber(value);

Why it matters (real-world impact)

Sensors that report a fault as JSON null are common. MQTT → json → change → range (drop, −5…45) → average-over-time → InfluxDB is a typical telemetry pipeline, and in it every null became a 0 reading. Mixed into a 10-minute average, one null among k real readings produced a dip of exactly k/(k+1) of the true value. A window of all nulls produced a flat 0. In our case, several years of a pool-temperature series collected hundreds of these fake dips before the cause was found. The data never looked like an error, only like a slightly cold reading.

Boolean inputs have the same problem in a different way: a status flag wired to a range node by mistake silently turns into 0/1 scaled values instead of being rejected.

Steps To Reproduce

Import this flow, deploy, and click each inject node. Look at the debug sidebar and the Node-RED log.

[
  {"id":"inj","type":"inject","name":"inputs","props":[],"repeat":"","once":false,"wires":[["fn"]]},
  {"id":"fn","type":"function","name":"null/true/false/\"\"/abc/42","func":"for (const v of [null, true, false, \"\", \" \", [], \"abc\", \"42\", 42]) {\n    node.send({ payload: v, input: JSON.stringify(v) });\n}\nreturn null;","outputs":1,"wires":[["rng"]]},
  {"id":"rng","type":"range","name":"drop, 0-100 -> 0-1","minin":"0","maxin":"100","minout":"0","maxout":"1","action":"drop","round":false,"property":"payload","wires":[["dbg"]]},
  {"id":"dbg","type":"debug","name":"","active":true,"complete":"true","wires":[]}
]

Result: the debug node shows outputs for null (0), true (0.01), false (0), "" (0), " " (0) and [] (0), as well as for the real inputs "42" and 42 (0.42). Only "abc" is dropped.

Example flow

See above.

Environment

  • Node-RED version: 5.0.7
  • Node.js version: 24.20.0
  • npm version: 11.19.1
  • Platform/OS: Debian
  • Browser: n/a (runtime behaviour)

Checked against the current master source of packages/node_modules/@node-red/nodes/core/function/16-range.js (latest release at time of writing: 5.0.7).

Activity

  1. dceejay commented on Oct 1, 2026

    @dceejay
    Member

    Initial thought is yes I agree - the whole point of the range node is to help scale numbers appropriately - so anything other than numbers should be dropped. But yes - it should handle numbers that are strings as they do occur quite a lot.
    If you have working fix that you can share as PR I would be happy to look at it - otherwise I'll try to get round to it soon.

  2. added a commit that references this issue on Oct 1, 2026
    d726a0d
  3. JMBMdes commented on Oct 1, 2026

    @JMBMdes
    Author

    Sure, submitting now.

    Thank you dceejay.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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