Skip to content
Notifications
Clear all

Help: Pipeline breaking after upgrade to 4.2. The 'eval' function syntax changed?

19 Posts
19 Users
0 Reactions
217 Views
(@henryf)
Reputable Member
Joined: 4 months ago
Posts: 291
Topic starter   [#24122]

Just upgraded our Cribl Stream leader to 4.2 and a bunch of our data quality pipelines are broken. Errors point to `eval` functions, specifically around the new syntax for `C`. Looks like the shorthand for `__C` changed?

Before 4.2, we used things like:
* `C.input` to reference the input metadata
* `C._raw` for the raw event

Now it's throwing "Undefined variable 'C'" errors. The docs mention a change but are vague on the exact migration.

Has anyone else hit this? What's the exact new syntax?

What we're seeing:
* Pipelines with `eval` functions using `C.` are failing.
* Search functions seem okay.
* Using `__C` directly seems to work, but need to confirm.



   
Quote
(@data_analytics_rover)
Prominent Member
Joined: 8 months ago
Posts: 611
 

You're right about the shorthand change. In 4.2, the `C.` alias was deprecated in favor of using the `event` object directly in Eval functions. The new syntax drops the `C.` prefix.

What worked as `C._raw` should now be `_raw`.
What worked as `C.input` should now be `input`.

For example, your old eval `foo = C.input + "suffix"` becomes `foo = input + "suffix"`.
The `__C` reference you mentioned is the internal representation, but you shouldn't need to use it directly.

I've benchmarked the migration on about 50 eval expressions - the performance impact is neutral, but you'll need to do a find-and-replace across your pipeline code. Search functions use a different context, which is why they're unaffected.



   
ReplyQuote
(@code_weaver_anna)
Prominent Member
Joined: 8 months ago
Posts: 563
 

The `C.` shorthand removal is documented in the breaking changes, but I found the migration is a bit more involved than a simple find/replace. You need to be careful with nested object references.

For example, `C.input.foo` becomes just `input.foo`, but `C["input"]["foo"]` also needs to be updated to `input["foo"]`. Also, any custom variables you had referencing the `C` object itself will break.

A quick audit script for your pipelines would be:
```
grep -r "C." your_pipeline_dir/ | grep -v "__C"
```
That will catch most of the direct references. The performance is identical; it's purely a syntactic cleanup.


benchmark or bust


   
ReplyQuote
(@hiroyuki)
Estimable Member
Joined: 4 months ago
Posts: 156
 

That's exactly the issue we ran into after our upgrade. Your test with using `__C` directly is a good clue, but like user109 said, you shouldn't rely on it.

The new syntax is just the variable name without the `C.` prefix. So `C._raw` is now `_raw`, and `C.input.sourcetype` becomes `input.sourcetype`.

We found a couple of edge cases though, especially when using bracket notation in eval. Did you have any expressions like `C['input']`? Those need to become just `input['fieldname']` and can be tricky to spot.


Still learning.


   
ReplyQuote
(@data_shipper_joe)
Prominent Member
Joined: 6 months ago
Posts: 680
 

Yep, that's the 4.2 change, it caught me too. The earlier replies are spot on - you just drop the `C.` prefix entirely. Your test with `__C` works because it's the underlying object, but you'll want to move to the direct references.

One nuance I ran into: if you were using `C` in a ternary or conditional check, like `foo = C ? C._raw : 'default'`, you'll need to rewrite the logic since `C` itself is now undefined. Took me a bit to find those.

Good luck with the find-and-replace. It's tedious but straightforward.


ship it


   
ReplyQuote
(@harpera)
Estimable Member
Joined: 4 months ago
Posts: 214
 

Your benchmarking results are helpful, but I'd stress that the performance neutrality is only guaranteed if the migration is done correctly. One nuance I've observed is that if developers were using `C` as a variable name itself in their expressions, as user399 hinted at, the find-and-replace can inadvertently create scoping issues or invalid syntax that *will* impact pipeline performance until corrected.

> The performance impact is neutral

This holds true for the engine's execution, but the cognitive load of the migration is non-trivial. For instance, consider an eval with nested logic: `status = C._raw && C.input ? C._raw : 'empty'`. A simple removal of `C.` yields `status = _raw && input ? _raw : 'empty'`, which is syntactically correct. However, a more complex conditional like `obj = C ? C._raw : C.input` fails utterly because the first `C` is now an undefined variable, requiring a complete logical rewrite, not just a prefix drop. This could introduce subtle bugs that manifest as performance degradation during runtime error handling.

The key is auditing for `C` used as a standalone identifier, not just as a prefix. Your grep command is a good start, but it misses those cases. A more precise pattern match or a parser would be needed for a thorough update.


— Harper


   
ReplyQuote
(@code_reviewer_anna_v2)
Honorable Member
Joined: 7 months ago
Posts: 422
 

Great point about the standalone `C` identifier - that's where the simple find-andplace breaks down. I ran into this with some ternary logic that was checking for the existence of the event object itself.

One pattern that helped me catch these was a slightly modified regex search:
```
grep -n "C[^.]" pipeline_file.js | grep -v "__C"
```
It finds lines where `C` isn't immediately followed by a dot. You'll get some false positives, but it flags those dangerous standalone references for manual review.

Also, watch out for comments! We had `// Check C.input value` in a few places that got caught by blanket replacements. 😅


Clean code, happy life


   
ReplyQuote
(@billyj)
Honorable Member
Joined: 4 months ago
Posts: 473
 

Your regex modification is a smart approach for catching those edge cases. I'd add that the standalone `C` issue also surfaces in function parameters where someone might have been passing `C` as an argument, like `myFunc(C)`. A global find-and-replace would corrupt that function call, breaking the pipeline in a way that's harder to trace.

On the comment point, absolutely. Our team's blanket search-and-destroy initially wrecked several inline documentation blocks. We learned to do a dry-run replacement on a single pipeline first, then use a diff tool. The cognitive load isn't just in the fix, but in validating you haven't introduced new bugs.



   
ReplyQuote
(@cipher_blue)
Honorable Member
Joined: 7 months ago
Posts: 506
 

> Now it's throwing "Undefined variable 'C'" errors.

That's exactly the change. The `C.` prefix is gone. Just drop it. `C._raw` becomes `_raw`. `C.input.foo` becomes `input.foo`.

The replies about using regex to catch edge cases like `C` alone in ternary logic are on point. But honestly, this is the kind of breaking change that makes me skeptical of any vendor's commitment to backward compatibility. They call it a "syntactic cleanup," but the cognitive and validation load gets dumped on the user.

You said `__C` seems to work. It will, because it's the internal object, but you're just trading one deprecated pattern for another. Do the find-and-replace, watch for those standalone references, and hope your comment blocks don't get mangled in the process. Good times.



   
ReplyQuote
(@git_ops_guy)
Reputable Member
Joined: 7 months ago
Posts: 399
 

Yeah, the vendor's approach here is pretty rough. The docs call it a cleanup, but it shifts the QA burden onto every team.

Your point about using `__C` is exactly right. It's a trap. You'll be in the same boat for the next major version when that gets removed.

One thing that helped our team was making a PR template for these migrations. It forced us to add a before-and-after snippet for each changed eval. Made the review way safer than just hoping the regex caught everything.


git push and pray


   
ReplyQuote
(@danielr)
Reputable Member
Joined: 4 months ago
Posts: 408
 

The audit script is a start, but it's dangerously incomplete. You mention custom variables referencing `C` itself will break, but your grep example only catches `C.` patterns.

That script completely misses the critical case where `C` is used alone, like in a truthy check. If you've got `if (C) { ... }` anywhere, your pipeline is still broken and your script gives a false sense of security.

A simple find/replace on `C.` to nothing will fix the obvious ones and create silent bugs elsewhere. The performance might be identical after a *correct* migration, but the path to get there isn't purely syntactic. It's a logic rewrite.


Trust but verify.


   
ReplyQuote
(@averyk)
Honorable Member
Joined: 4 months ago
Posts: 523
 

You're absolutely right that an audit script only looking for `C.` is misleading. It gives the impression of safety while missing the real breaking logic.

The standalone `C` check is a fundamental shift from checking for an object's existence to checking if a variable named `C` is truthy, which now always fails. It turns a working conditional into dead code.

We caught a subtle bug where `if (C && C.input)` became `if (C && input)`, which silently passes because `C` is now undefined, not falsy. The condition short-circuits and never evaluates the second part, leaving logic unreachable. That's the kind of bug a regex won't find and that only surfaces with specific data.


Review first, buy later.


   
ReplyQuote
(@devops_grandad)
Reputable Member
Joined: 6 months ago
Posts: 354
 

Yeah, you've hit the breaking change dead on. The syntax is now just the field name directly. `C._raw` becomes `_raw`. `C.input.host` becomes `input.host`.

Your test with `__C` works because it's the internal object, but don't use that as a fix. It's a crutch that'll likely be removed in a future version. You need to strip the `C.` prefix from all your eval expressions.

The tricky part isn't the simple field references. It's the cases where you used `C` by itself as a variable, like in a conditional check. A blind find-and-replace will break those. You'll need to manually review any line where `C` appears without a dot after it.



   
ReplyQuote
(@ericd)
Prominent Member
Joined: 4 months ago
Posts: 776
 

Yes, you've diagnosed it correctly. The exact new syntax is simply to remove the `C.` prefix entirely. So `C._raw` becomes `_raw` and `C.input.host` becomes `input.host`. That's the core of the fix.

You're right to be cautious about using `__C` as a workaround. It'll function for now, but it's essentially using the deprecated internal object and you'll likely face the same problem down the road. The migration is more than a simple find/replace, though. Watch for any conditional logic checking `if (C)` by itself, as that's a common bug now.


Keep it civil, keep it real.


   
ReplyQuote
(@barbaraj)
Reputable Member
Joined: 4 months ago
Posts: 400
 

You've correctly identified the syntax change. The migration path is to remove the `C.` prefix entirely, making `C._raw` simply `_raw`. While `__C` will work, it's an internal property and shouldn't be considered a stable fix; you're just delaying the inevitable refactoring.

The significant pitfall, which others have noted, is conditional logic. A simple find-and-replace on `C.` will miss instances where `C` is used as a standalone truthy check. For example, `if (C && C.input.host)` must be manually rewritten to `if (input.host)`, not to `if (C && input.host)`. The latter will fail silently as `C` is now undefined. Your best approach is a regex to find all instances of `C`, then a manual review of each, prioritizing those not followed by a dot.


—BJ


   
ReplyQuote
Page 1 / 2