Hey everyone, tried debugging this with Claude, but it didn’t really work, so I was wondering if anyone could help. The explanation is below:
I have a Webhook → IF v2 workflow where the IF compares a query parameter against a Project Variable. Both resolve to the same string, but the IF always routes FALSE. The only fix is replacing the variable reference with the literal value, which defeats the purpose.
Setup
- n8n Cloud, version 1.123.43
- Global variable: key
staff_key, valueb8133d71b3f96bc630e3bb0a, scope Global - Webhook receives URL:
?staff_key=b8133d71b3f96bc630e3bb0a - IF v2 single condition:
- Value 1:
{{ $json.query.staff_key }}(expression) - Operator:
String → is equal to - Value 2:
{{ $vars.staff_key }}(expression) - Options → “Convert types where required”: ON
- Value 1:
Diagnostic
I inserted a Code node between the Webhook and the IF to inspect the values in raw JavaScript:
const fromUrl = $json.query.staff_key;
const fromVar = $vars.staff_key;
return {
fromUrl,
fromUrl_length: fromUrl?.length,
fromUrl_type: typeof fromUrl,
fromVar,
fromVar_length: fromVar?.length,
fromVar_type: typeof fromVar,
strict_equal: fromUrl === fromVar,
loose_equal: fromUrl == fromVar
};
Output:
fromUrl: "b8133d71b3f96bc630e3bb0a"
fromUrl_length: 24
fromUrl_type: "string"
fromVar: "b8133d71b3f96bc630e3bb0a"
fromVar_length: 24
fromVar_type: "string"
strict_equal: true
loose_equal: true
So at the JS level, the two values are byte-identical, same type, and both === and == return true.
Things I tried
- Toggling “Convert types where required” both ON and OFF — no difference, both route FALSE.
- Deleting and recreating the variable to rule out trailing whitespace.
- Re-saving the workflow and re-listening for test events between attempts.
- Putting
{{ $json.query.staff_key }}while Value 2 with the literal stringb8133d71b3f96bc630e3bb0aand deleting the global variable staff_key — This immediately works and discriminates correctly.
Question
Why does the IF v2 node refuse to evaluate $vars.X === $json.Y as true when raw JavaScript confirms they are strict-equal strings? Is there a known type-wrapping difference between how $vars and $jsonare presented to the IF node’s internal evaluator? Is there a workaround that preserves the variable reference?
Workflow currently runs fine with the literal value, but I’d rather route secrets through Variables for a future rotation.