On the reported Ignition 8.1.43 system, calls to scripts from views failed while the log showed TypeError: unhashable type: 'dict' during project-script-module clearing. The trace points to script-module invalidation, not directly to the view’s one-second now(1000) binding or its transform.
Read the failure at the module-clearing boundary
The stack trace is the first diagnostic boundary. It passes through ScriptManager.clearProjectScriptModules and PerspectiveModuleRpcImpl.designerScriptsModified. That places the logged exception in the path that clears project script modules after a designer script modification. It does not show a timer transform executing, nor does it identify a view binding as the operation that raised the exception.
Jython reports “unhashable” when code attempts to use a mutable value such as a dictionary as a hash key. A list is also mutable and unhashable. The log’s occasional list variation is therefore a related symptom category, but it does not identify which value or operation supplied that object. Avoid treating the displayed type as proof that a particular view property returned the offending value.
Separate two questions during diagnosis: what operation failed, and what user action preceded it? The trace answers the first at the script-module clearing boundary. A view being open or a timer being active when the error appears is temporal correlation; test it before assigning causality.
Record a reproducible baseline on version 8.1.43
Keep the reported version, 8.1.43, attached to every reproduction result. Record the exact sequence that triggers the error, whether the error appears while editing or saving project scripts, which view is open, and whether its scripts are being called. Capture the complete log stack trace, including whether the unhashable type is dict or list.
Use a controlled test project or a copy of the affected project. Change one condition at a time and repeat the same action sequence. If an error only appears intermittently, note the number of repetitions and the preceding designer action rather than summarizing it as “random.” This makes it possible to distinguish an event associated with a module reload from one associated with timer execution.
Check 1: Confirm that the failing log entry contains clearProjectScriptModules and designerScriptsModified. Expected reading: both appear in the reported stack; if the new failure has a different stack, diagnose that separate execution path.
Test whether the view timer is a trigger
The described timer is a custom object whose action binding evaluates now(1000) every second and runs a transform. The described intent is to use an enable bit, set a target timestamp, and disable the timer after the delayed action completes. The transform code and object configuration are not available in text, so do not infer its return value or internal state behavior from the description alone.
Use an A/B test rather than removing the design based on correlation:
- Run the documented reproduction sequence with the timer binding and transform active. Record whether the module-clearing exception occurs.
- Disable only the timer binding or remove it from the test view, leaving the project scripts and the same designer script-edit/save sequence unchanged. Repeat the sequence.
- Restore the timer and compare results across repeated runs. Separately test ordinary timer activity without modifying project scripts, and project-script modification without the timer active.
If the same exception occurs during script modification with the timer disabled, the timer is not required to trigger that failure. If it occurs only with the timer active, inspect the transform and the values it passes to scripts, then repeat with a minimal transform. Neither result alone proves the underlying defect, but the comparison localizes the conditions necessary for reproduction.
Check 2: Compare full stack traces from both test conditions. Expected reading for a reproduced instance of this failure: the same module-clearing path; a different stack indicates that the timer test exposed another problem.
Inspect project-library import and reload paths
The failure path involves project script-module clearing, so inspect how project library scripts are imported and called around script edits and module reinitialization. In particular, check whether one project library script imports another. The diagnostic discussion identifies nested project-library imports as a condition worth checking, but does not establish that they caused this installation’s error.
Search project scripts for import statements, then map which scripts import other project scripts and which view or gateway actions call them. Test a simplified case with the relevant call path, changing one import relationship at a time. If a minimal project reproduces the exception only with a particular import arrangement, preserve that case for further diagnosis. Do not broadly remove imports or rewrite working scripts before the test isolates a relationship.
Also compare when script calls happen relative to module reinitialization. A call during or immediately after a script-module reload may exercise a different path from a call made during steady-state operation. Record the order of edits, saves, reload-related log entries, and calls; do not conclude that a gateway event or nested import is responsible without a repeatable comparison.
Check 3: Repeat the same script call after the edit/reload activity has stopped. Expected reading: determine whether the exception is confined to the modification/reinitialization sequence or persists during steady-state calls.
Keep timer timing separate from the import exception
A periodic binding and a delayed action solve different timing problems. The described now(1000) binding supplies a recurring evaluation; it is not itself evidence of an import failure. The enable bit and target timestamp are application logic for deciding when the action is due. Validate that logic independently from script-module errors.
For the timer test, record when the enable bit becomes true, the target timestamp set by the view logic, when the transform sees the deadline reached, and when the action disables the timer. Check whether the intended action occurs once or repeats, and whether it stops after disable. The source does not provide the transform code, timestamp units, or exact property paths; inspect those in the project rather than assuming their names or semantics.
If the timer itself behaves incorrectly, reduce the transform to the smallest test that reads the enable state and compares the current time to the stored deadline. Verify boundary behavior around the deadline and confirm that disabling the binding stops recurring work. Treat a timer defect and a module-clearing exception as separate until the A/B test links them.
Check 4: Observe the timer state and action independently of script edits. Expected reading: the action follows the configured enable/deadline logic and ceases when the timer is disabled; any timing discrepancy belongs to the timer investigation, not automatically to the import trace.
Verify the correction across both operating conditions
After making a targeted change based on a reproducible test, verify both steady-state script execution and script modification. A fix that only hides the view error, or only avoids editing scripts while the timer is active, does not demonstrate that both conditions work. Keep the change narrow enough that the before/after comparison identifies what changed.
- Open the affected view and exercise the script calls that previously failed. Expected reading: calls complete without the module-clearing exception.
- Perform the project-script edit or save sequence associated with
designerScriptsModified. Expected reading: the logs do not show the sameTypeErrorinclearProjectScriptModules. - Repeat with the timer enabled and disabled, using the same sequence. Expected reading: results remain consistent across repeated trials, with no new stack trace tied to the timer condition.
- Inspect logs after each test and record the full stack if any error remains. Expected reading: either no recurrence of the original trace or a clearly different failure path that can be diagnosed independently.
FAQ
Why does Ignition report “unhashable type: dict”?
Jython raises this when a mutable object such as a dictionary is used where a hashable key is required. In the reported trace, the exception appears while project script modules are being cleared; the trace does not identify the dict’s origin.
Why does the stack trace mention a view if the timer may not be the cause?
The reported path includes Perspective handling a designer script modification and then clearing project script modules. A view path or open view can be context, but the stack does not show the timer transform as the failing operation.
Why does the error sometimes say “unhashable type: list”?
Lists, like dictionaries, are mutable and unhashable in Python/Jython. Record the exact type and full stack each time; the type variation does not by itself identify a different root cause.
Why check imports between project library scripts?
The exception occurs in project script-module clearing, and nested project-library imports are a relevant condition to test around module initialization. Isolate imports one at a time; their presence alone does not prove causation.
How do I verify the timer is not triggering the import error?
Repeat the same script-edit and call sequence with the timer active, then with only its binding disabled. Compare the complete traces; the final verification is no recurrence of the original module-clearing exception in either condition across repeated trials.