Rapid SCADA: Why Does GetCurCnlDataExt JSON.parse Fail?

Ryan Tanaka10 min read
HMI / SCADAOther ManufacturerTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

The banner over the scheme reads Error updating scheme data, the graphics draw fine, and every value box stays blank. Press F12 and the console tells you what actually broke: Error processing request 'ClientApiSvc.svc/GetCurCnlDataExt': JSON.parse: unexpected character at line 1 column 2810 of the JSON data. One of the input channels feeding that scheme is pushing a character into the response that terminates the JSON early, so the client throws before it distributes a single value. The character is almost always in text attached to a channel — the unit string first, formula-generated output second. Fix it in the configuration database; nothing you do in the browser will help.

Confirm the Failure Is in the Data Call

Start here. It takes thirty seconds. Reload the view with the console open and read which requests succeed.

  • SchemeSvc.svc/GetSchemeDoc, GetComponents, GetImages and GetLoadErrors all successful when the view loads (for example Scheme.aspx?viewID=200) — the view file, the Scheme plugin and the web host are fine.
  • ClientApiSvc.svc/CheckLoggedOn successful every few seconds straight through the outage — session, authentication and the WCF endpoint are fine.
  • Only ClientApiSvc.svc/GetCurCnlDataExt failing, roughly once per second — the payload content is the fault.

On the Server side, check that the data path is alive: the service log should show the input channels read from the configuration base and the ScadaWeb user authenticated from 127.0.0.1. If Server is serving its active channels and Webstation is logged in, the pipe is open. What comes back through it is malformed. The same signature turns up on Windows XP x32 with Server 5.0.2.0 and on Windows 7 32-bit with Rapid SCADA 5.5.1 — this is not an OS or version defect.

What you see What it means Where to look
Scheme draws, values blank, error banner above the scheme The poll response never parses, so no value is ever applied Console, the utils.js log line
JSON.parse: unexpected character at line 1 column 2810 A string field closed early, or a byte did not survive the response encoding Raw response body at that offset
Offset drifts a few characters poll to poll (2807-2812) Same broken field; numeric values ahead of it change width The channel whose text sits at that offset
CheckLoggedOn keeps succeeding during the outage Not authentication, not the session, not the web server Nowhere. That is not the fault.
Fault appears, runs for minutes, clears itself The trigger is a transient channel state, not a typo you can see Communicator line logs for the same window
Communicator logs a link error in the same window Channels go undefined or to zero; formulas consuming them can go non-finite Formulas referencing those channels
Server log: cannot access ScadaServerSvc.txt, used by another process Another process holds the log file open Unrelated to scheme data

Why One Character Kills Every Poll

The Scheme plugin calls GetCurCnlDataExt about once a second and gets back a single JSON object carrying, per channel, the current value, the status, the formatted display text and the unit. The client parses it in one shot with JSON.parse. There is no per-channel error handling on that path — the parse either succeeds and every component updates, or it throws and the whole view stays stale. That is why one bad channel out of a hundred and sixty blanks the entire scheme.

Channel text is transmitted without additional encoding, by design. Escaping every string on every one-second poll costs throughput, and on this refresh rate throughput was chosen over safety. The consequence lands on you: whatever text you put into the configuration base has to survive serialization and the response encoding unchanged.

Two things break it. A character that needs escaping and does not get it — a double quote, a backslash, a control character — closes the string early and the parser hits an unexpected token at exactly that index. Or a non-ASCII character mangled by the response encoding leaves a byte the parser cannot place. Either way the reported column is the position of the damage, and because the payload layout is fixed, the column barely moves between polls. A stable 2807-2812 across dozens of failures means one field, with a couple of digits ahead of it changing width.

Pull the Offending Character from the Network Tab

  1. F12, Network tab, filter on GetCurCnlDataExt. On a permanent fault every request is bad; on an intermittent one, leave it recording until you catch a failure.
  2. Select a failed request and open the raw response body — not the pretty-printed tree, which will not render malformed JSON anyway. Copy it.
  3. Go to the offset from the console message. The payload is one line, so column 2810 is character index 2810. Read fifty characters either side.
  4. Search backwards from the offset for the nearest channel-number key. That channel carries the bad text.
  5. Record the character code, not the glyph. A degree sign, a micro sign, a superscript three, a non-breaking space and a typographic quote all look harmless in a screenshot.
// Paste the copied raw response between the backticks, run in the browser console.
var body = `...paste here...`;
var pos  = 2810;                    // column from the JSON.parse message
console.log(JSON.stringify(body.substring(pos - 60, pos + 60)));
console.log(pos, body.charCodeAt(pos - 1), body.charCodeAt(pos));

// List every character outside plain ASCII with its index
var bad = [];
for (var i = 0; i < body.length; i++) {
    var c = body.charCodeAt(i);
    if (c < 32 || c > 126) bad.push(i + ":" + c);
}
console.log(bad.join(" "));

The message wording is browser-specific — Firefox reports a line and column, Chromium reports a position — but the number means the same thing.

Clean the Units and Number Format Tables

In Administrator, the configuration base tables sit under the System and Dictionaries (Справочники) nodes of the tree. Two of them own nearly all the text that reaches the poll response.

  • Units (Размерность) — first place to look. Replace anything that is not plain ASCII: m3/h instead of a cubic-metre glyph, degC instead of °, and drop math symbols such as ≤ ≥ × ÷ · along with typographic quotes and dashes.
  • Number formats (Форматы чисел) — check the format strings and decimal counts. A format that lets a collapsing value render in exponential notation is a nuisance even when it parses.

Sweep channel names too, and anything pasted in from Word or Excel: those carry non-breaking spaces (U+00A0) and curly quotes that render identically to their ASCII twins on screen. A Units table that looks clean is not proof — in the field case that kept recurring, the table showed nothing suspicious at all. Check byte values, not glyphs.

After editing, upload the configuration to Server and reload the page with Ctrl+F5. The scheme document, components and images are fetched once at view load, so a plain refresh can hand you a cached copy of the old view.

Guard Formulas That Can Return Non-Finite Values

This is the variant that hides from a static review. The fault appears, runs a minute or two, clears itself, then returns a few minutes later — windows like 12:01:04 to 12:02:10 and 12:04:04 to 12:06:10, with single successful CheckLoggedOn calls sprinkled through them. Line up those windows against the Communicator log and you find link errors in the same minutes: remote equipment behind GSM/GPRS modems such as the iRZ ATM2-485 drops out, the channels behind it go undefined or fall to zero, and any formula dividing by one of them stops returning a finite number.

.NET does not throw on double division by zero; it returns Infinity. Formatting an Infinity or a NaN puts a culture-dependent symbol or word into the channel text, and that is the math symbol you were told to hunt for. It also explains the self-recovery: when the link comes back, the divisor is non-zero again, the text goes numeric again, and the scheme repaints without anyone touching it. The same shape appears when a result swings across decades — a value above 1 that collapses to 0.000... — because the formatted output changes form as the magnitude changes.

// Never let a channel formula return Infinity or NaN.
// Confirm the function names against the formula editor in your version.
double den = Val(101);
double res = Math.Abs(den) < 1e-9 ? 0.0 : Val(100) / den * 100.0;
if (double.IsNaN(res) || double.IsInfinity(res))
    res = 0.0;              // or hold the last good value
return res;

Guard every divisor, every logarithm and square-root argument, and every counter difference that could go negative across a rollover. Then pin the display: fix the decimal count in the number format so a collapsing value renders as 0.000 instead of an exponent.

Verify the Fix

  1. Reload the view with the console open and watch for an unbroken run of Request 'ClientApiSvc.svc/GetCurCnlDataExt' successful. Ten clean polls prove nothing on an intermittent fault — you want it clean across a full comm-error cycle.
  2. Force the trigger. Drop the field link deliberately, disconnect the antenna or power the remote device down, and confirm the scheme keeps updating the surviving channels while the affected ones show as invalid.
  3. Re-run the non-ASCII scan on a fresh response body. The list should come back empty.
  4. Cross-check timestamps. If Communicator link errors no longer coincide with parse failures in the console, the formula guards are holding.

Stop Chasing These

  • The log file lock. The process cannot access the file 'C:\SCADA\ScadaServer\Log\ScadaServerSvc.txt' because it is being used by another process means an editor, a tail viewer or an antivirus scanner is holding the log — or the console application and the service are running at once. Clear it, but it is not why your scheme is blank.
  • Reinstalling anything. The failure is data-driven. In the field cases nothing had been installed or changed in Windows before it started.
  • Authentication, firewall, IIS. CheckLoggedOn returns successful right through the outage.
  • Communicator. Line logs stay adequate and data keeps landing in the archive — that is why the historical tables look normal while the scheme is dead. Link errors are the trigger, not the mechanism.
  • Bisecting channels and calling it solved. Unchecking every channel and formula and re-enabling them in blocks does clear the error and is a fair way to corner a static bad string. On a state-dependent fault it only proves the trigger state was absent while you tested; the error returns.
  • Eyeballing the Units table. Non-breaking spaces and typographic quotes are invisible in a screenshot.

When to Escalate

Two conditions end your side of the work: the offset lands inside a field you cannot map to any Units, Number formats, channel name or formula entry, or the character scan comes back empty while the parse still fails. Capture the raw GetCurCnlDataExt response body from the Network tab for a failing poll, the Units and Number formats tables, the Server log for the same window, and the steps that reproduce it on a default configuration, then open a case through the official Rapid SCADA support channels. Without the raw response nobody can separate a serialization defect from a configuration problem.

FAQ

Can I ignore the ScadaServerSvc.txt file lock error while chasing this?

Yes, for this fault. The lock only means another process is holding the log file — close the editor or viewer, or stop the console application if the service is also running. It has no effect on GetCurCnlDataExt or on scheme updates.

Does a Communicator link error by itself cause 'Error updating scheme data'?

No. A link error marks the affected channels invalid, which shows as blanks or dashes on the scheme while the rest keeps updating. It becomes a parse failure only when a formula consuming that channel returns Infinity or NaN and the formatted text picks up a non-ASCII symbol.

Can I use degree, cubic-metre or micro symbols in the Units table?

Treat them as unsafe. Channel text is sent without extra encoding for throughput reasons, so use ASCII equivalents such as degC and m3/h; if you need the glyph, confirm the raw poll response parses cleanly before you release the view.

Back to blog