Symptom: Silent Return on an Invalid Path
Calling system.db.clearNamedQueryCache with a path that does not match any named query produces no error. The call completes and returns None, and execution continues past it. The function reference says a GatewayException is thrown for a malformed path, but the implementation does not throw one.
The behavior is easy to reproduce from a Perspective component event script, which runs in gateway scope:
def runAction(self, event):
system.perspective.print("start test")
from java.lang import Throwable
try:
ret = system.db.clearNamedQueryCache(path = "blablabla")
system.perspective.print("ret: %s" % (repr(ret)))
except Throwable as t:
system.perspective.print("caught Throwable: %s" % (repr(t)))
except Exception as e:
system.perspective.print("caught Exception: %s" % (repr(e)))
system.perspective.print("end test")
self.props.value = 0
The expected output is caught Throwable. The actual output is start test, ret: None, end test. Neither the Java Throwable handler nor the Python Exception handler fires.
Mechanism: Void All the Way Down
The scripting function wraps internal Java methods that are declared void at every layer. Nothing below the script call reports whether a cache entry existed, whether one was evicted, or whether the path resolved to a query at all. The scripting layer therefore has nothing to return except None, and it does not validate the path before handing it down.
Three practical consequences follow:
-
Success and failure look identical. A valid path with a populated cache, a valid path with caching disabled, and a typo all return
Nonewith no exception. - try/except around the call is dead code. No exception handler around this function will ever run for a bad path, so any error UI or alarm built on that handler never fires.
- The failure surfaces later as stale data. A cache clear that silently misses leaves the old result set in place until the query's configured cache duration expires. Operators see stale values; the script log shows nothing.
The documentation and the implementation disagree. Treat the implementation as the contract: build validation outside the function rather than waiting for an exception that is not coming.
Symptoms Versus Causes
| What you see | Likely cause | What decides it |
|---|---|---|
Call returns None, no exception, data still stale |
Path string does not match the named query (typo, wrong folder, old name after a rename) | Compare the string character-for-character with the path in the Designer Named Queries tree |
Call returns None, data refreshes only after a delay |
Clear missed; cache expired on its own timer | Time the refresh against the query's configured cache duration |
Call returns None, data was never stale |
Caching not enabled on that named query, so there was nothing to clear | Check the query's caching settings in the Designer |
| Exception handler never fires on garbage input | Function does not validate paths; documented GatewayException is not raised |
Run the reproduction above with a nonsense path |
Switching path= keyword to a positional argument changes nothing |
Argument style is not the cause; behavior is identical either way | Run both forms; output matches |
Approach Comparison
Several ways exist to get feedback out of a function that gives none. They differ in whether they work at all, what they cost at runtime, and what they catch.
| Approach | Catches bad paths? | Runtime cost | Side effects | Verdict |
|---|---|---|---|---|
Wrap the call in try/except (Throwable or Exception) |
No | None | False confidence | Non-functional; remove or replace |
| Change argument style (positional instead of keyword) | No | None | None | No effect on this function |
| Pre-validate against a maintained registry of cached query paths | Yes, deterministically | Set lookup | Registry must be kept in sync with the project | Recommended for runtime |
Pre-validate by executing the query (system.db.runNamedQuery) first |
Yes, via the run's own error | Full database round trip | Executes the query; unsafe for update/insert queries; repopulates cache right before clearing it | Avoid at runtime |
| Stale-data functional test | Yes, and proves the clear actually took effect | Manual, one-time | Requires writing test data | Required at commissioning |
Use two layers: a registry-checked wrapper at runtime, and a stale-data test at commissioning and after any named query rename or move. The wrapper stops typos from ever reaching the silent function; the test proves the path that passes the wrapper actually evicts the cache.
Recommended Guard: Registry-Checked Wrapper
Before anything else, confirm which named queries in the project have caching enabled. Only those belong in the registry; clearing a non-cached query is a no-op and signals a design mistake if it appears in code.
- Inventory cached queries. Open each named query in the Designer and check its caching settings. Record the exact path as shown in the Named Queries tree (folder and name). Do not move on until every cached query is listed.
-
Create a project library script holding the registry and the wrapper. The script name and example path below are placeholders; replace them with your own.
Confirm: the script saves without syntax errors and the gateway logger
NQCacheappears once the function is first called. -
Replace every direct call to
system.db.clearNamedQueryCachein views, event scripts, and gateway scripts withnqcache.clear(...). A project-wide search for the function name finds them. Confirm: the search returns hits only inside the library script. -
Handle the wrapper's exceptions where the call originates. In a Perspective event:
def runAction(self, event): try: cleared = nqcache.clear("Folder/QueryName") system.perspective.print("cache clear requested: %s" % cleared) except (ValueError, TypeError) as e: system.perspective.print("rejected: %s" % e)Confirm: passing
"blablabla"now printsrejected: Unknown or uncached named query path: 'blablabla'instead of silently returning. - Log wording matters. The log line says "requested", not "cleared". The underlying function cannot confirm eviction, so the log must not claim it.
Pitfalls: Renames, Scope, and Argument Style
-
Renaming or moving a named query breaks clears silently. Every call pointing at the old path keeps returning
Nonewhile the new query's cache is never touched. With the wrapper in place, the old path is still in the registry and passes the check, so update the registry in the same change as the rename, then rerun the stale-data test. -
Argument style is not the fault. Many older
system.*functions handle keyword arguments poorly, so trying the positional form is a reasonable first check. For this function,clearNamedQueryCache("blablabla")andclearNamedQueryCache(path = "blablabla")behave identically. Pick one style and keep it consistent inside the wrapper. - Scope determines which project's cache is targeted. Perspective scripts run in gateway scope with an implied project. Gateway event scripts and scripts called from outside a project context may use a different signature; read the scope-specific syntax in the function reference for your Ignition version before reusing the wrapper there. A clear aimed at the wrong project fails exactly as silently as a typo.
-
Catching
java.lang.Throwabledoes not help. It is the right pattern for surfacing Java exceptions that Python'sExceptionmisses, but here no exception exists at either layer. Keep the pattern for othersystem.dbcalls; do not rely on it for this one. - Clearing a non-cached query proves nothing. If caching is off, the query always hits the database and the clear has no observable effect. The registry excludes these queries so a clear call against one is rejected rather than mistaken for success.
Commissioning Verification: Stale-Data Test
The wrapper proves a path is in the registry. Only a functional test proves the path evicts the cache. Run this once per cached query at commissioning and again after any rename, move, or project copy.
- Confirm caching is active on the target query in the Designer and note its cache duration. The test must finish well inside that window, or natural expiry will mask a failed clear.
-
Run the query with a fixed parameter set using
system.db.runNamedQueryfrom the Script Console or a test view. Record the returned value for one specific row. - Change that row directly in the database using a database tool or a test table, not through the named query.
- Rerun the query with the identical parameter set. Expect the old value. If the new value appears, caching is not active for that parameter set; fix the query settings before continuing.
-
Call
nqcache.clear()with the query's path. Confirm theNQCachelog entry appears in the gateway logs. - Rerun the query with the identical parameter set. Expect the new value. If the old value persists, the registry path does not match the query or the call targeted the wrong project; correct the path and repeat from step 3.
-
Run the negative test. Call the wrapper with a nonsense path and confirm it raises
ValueError. Then call the rawsystem.db.clearNamedQueryCachewith the same nonsense path and confirm it still returnsNonewithout raising. If the raw call now raises, the platform behavior has changed after an upgrade; review every handler around cache clears before signing off.
FAQ
What happens if I pass a misspelled path to system.db.clearNamedQueryCache?
The call returns None and raises nothing, despite the documented GatewayException. The real query's cache stays populated and clients receive stale data until the configured cache duration expires.
What happens if I call clearNamedQueryCache with a positional argument instead of path=?
Nothing changes. Both clearNamedQueryCache("x") and clearNamedQueryCache(path = "x") return None silently for an invalid path, so argument style is not the fix.
What happens if I wrap clearNamedQueryCache in try/except java.lang.Throwable?
The handler never runs for a bad path because the function and its internal Java methods are void and perform no path validation. Replace the try/except with a pre-check against a registry of known cached query paths.
What happens if I clear the cache on a named query that has caching disabled?
The call returns None, identical to a successful clear, and has no effect because every execution already hits the database. Keep such queries out of your clear registry so these calls are rejected instead of looking like success.
How do I confirm clearNamedQueryCache actually cleared the cache?
Run a stale-data test: execute the query, change the underlying row directly in the database, confirm the rerun returns the old value, call the clear, and confirm the next rerun returns the new value. Finish with a negative test showing a bogus path is rejected by your wrapper.