Problem Overview
User-Defined Data Types (UDTs) in TIA Portal are reusable PLC data type templates that group related tags under a single type definition. Once a UDT is instantiated in a global Data Block (DB), in a Function Block (FB) static section, or as a multi-instance inside a higher-level FB, any change to the UDT source forces TIA Portal to reconcile every dependent instance. The most common symptom is a "Declaration inconsistent" or "Type conflict" error when opening the affected DB, accompanied by a red status indicator in the project tree and a blocked online download to the S7-1200 or S7-1500 CPU. The Siemens Industry Online Support portal classifies this as a type-version mismatch in the STEP 7 information system.
The failure chain typically observed in production engineering programs:
- Engineer creates a UDT (e.g.,
typeAxisBasic) with N members covering axis status, control, and fault words. - Engineer creates a global DB and declares one or more variables of that UDT, or instantiates the UDT as the static section of an FB.
- Engineer reopens the UDT editor in the "PLC data types" folder and adds, removes, renames, reorders, or widens a member.
- On the next compile, the dependent DB or FB static section shows red entries in the declaration view; opening the block in the standard editor is blocked or returns a "Declaration inconsistent" error.
- Compile of the software unit or program fails; the "Go online" path is allowed only with a download that is refused by the CPU because the offline signature and the online runtime image no longer agree.
This article documents the diagnostic procedure, three resolution workflows (per-block Update declaration, project-wide Compile all, and the addressing-mode switch), the underlying type-versioning mechanism introduced in TIA Portal V15, and the design practices that prevent the condition from recurring in long-lived programs targeting the SIMATIC S7-1500 and S7-1200 families.
Root Cause Analysis
TIA Portal tracks the structure of every UDT instance against the type definition that produced it. When the type is edited, the existing instances become stale and TIA Portal marks them as inconsistent. Three structural change categories are responsible for almost every error encountered in production programs.
| UDT Edit | Effect on Existing Instances | Severity | Recovery |
|---|---|---|---|
| Append new member at end of UDT | All existing offsets preserved; new offset added at end | Low | Single "Update declaration" pass |
| Insert new member in middle of UDT | Offsets of all subsequent members shift by member size | High | Update declaration + re-bind HMI tags and any absolute references |
Widen existing member (e.g., INT → DINT) |
Element size changes; downstream offsets shift | High | Update declaration + re-bind HMI tags and any absolute references |
| Remove member | Offsets of all subsequent members shift up; retained values from old offsets become orphaned | High | Update declaration + re-bind HMI tags + verify retained data |
| Rename member | Symbolic references update automatically; absolute references do not | Medium | Update declaration; depends on addressing mode |
Change member data type to incompatible type (e.g., REAL → BOOL) |
Type conflict; downstream offsets shift unpredictably | Critical | Re-create the UDT, do not edit in place |
The compilation error is not a defect - it is a deliberate safety mechanism. TIA Portal refuses to generate code for a DB whose declared structure does not match the type it claims to instantiate because the resulting runtime image in the CPU would not match the offline project. Downloading such code could corrupt the process image, scramble retained values, and overwrite live HMI tag bindings with garbage.
Diagnostic Procedure
Before applying a fix, confirm the failure mode and the scope of the damage. The following sequence isolates the affected block list and identifies the exact structural change that triggered the inconsistency.
- Read the compiler output. In the project tree, select the PLC_1 station and open Info > Compile. The first error message identifies the inconsistent block; subsequent messages cascade from the same root cause and can be ignored for the first pass.
- Right-click the inconsistent DB in the project tree and choose Compile > Software (rebuild all blocks). The full rebuild forces TIA Portal to re-evaluate every type reference and produces a definitive list of inconsistent blocks, including any FB static sections, multi-instance DBs, and other global DBs that reference the same UDT.
- Compare the current UDT with the last known-good version. Open the UDT in the "PLC data types" editor and check the structure, member order, and data types. If project history is enabled, use Project > Project history to diff against the previous commit.
-
Document the offsets that will change. For every UDT member inserted or widened in the middle of the structure, list the byte offset shift and the symbolic names of any HMI tag, OPC UA node, or
POKE_BLK/GET/PUTinstruction that references the affected block by absolute address. -
Back up the project before applying any fix. Use Project > Archive to produce a
.zaparchive of the current state, then save the archive to a path outside the TIA Portal working directory.
If the project is under source control, tag the inconsistent revision with a marker so the recovery can be reverted if the downstream impact is worse than the original error.
Resolution Method 1 - Per-Block Update Declaration
The safest and most surgical recovery path is to update the declaration of each affected block individually. TIA Portal performs a member-by-member reconciliation that preserves the symbolic names of unchanged members and inserts the new members at the offsets dictated by the new UDT structure.
- Open the project tree and expand PLC_1 > Program blocks.
- Double-click the inconsistent DB. TIA Portal displays a dialog stating that the block declaration is inconsistent with the referenced type. Confirm the dialog.
- The DB opens in the declaration view. New, removed, and renamed members are highlighted in red.
- Right-click anywhere in the declaration table and select Update declaration. TIA Portal reconciles the local declaration against the current UDT, removes members that no longer exist, inserts new members, and re-applies the offsets.
- Save the DB with Ctrl+S and recompile. The red highlights disappear and the block compiles cleanly.
- Repeat for every block listed in the rebuild output. The typical case is a handful of DBs and one or two FB static sections.
For an FB that uses a UDT in its static section, the workflow is identical. Open the FB, switch to the static section, and right-click to Update declaration. The instance DB that the FB generates on download is regenerated from the updated static section automatically on the next compile.
Resolution Method 2 - Project-Wide Compile All
For larger programs where the same UDT is referenced in tens or hundreds of blocks, the per-block workflow becomes impractical. TIA Portal provides a project-wide consistency pass that performs the declaration reconciliation in one operation.
- In the project tree, right-click the PLC_1 station.
- Choose Compile > Software (rebuild all blocks). This is the full project consistency pass; the lighter Compile > Software (only changes) option does not always pick up UDT-driven inconsistencies because it only recompiles dirty blocks.
- The compile output lists every block whose declaration was reconciled. Each entry is marked as "updated" or "recompiled".
- If the compile completes with warnings only (no errors), the project is consistent. Errors that remain typically point to blocks that contain code referencing removed or renamed UDT members and require manual code edits.
Empirical results from production migrations show that the project-wide "Compile all" workflow resolves approximately 50-60% of the UDT-related declaration errors without further manual intervention. The remaining errors are concentrated in three areas:
- Function blocks whose Input, Output, or InOut parameters use the modified UDT and contain code that referenced the old member list.
- Multi-instance FBs whose static section is itself a UDT - the multi-instance update requires an explicit recompile of the parent FB.
- Blocks that use the UDT in Temp or Static sections together with SCL
REGIONblocks that re-cast the UDT to a different type.
Resolution Method 3 - Switching Addressing Mode
TIA Portal supports two addressing modes for tag access: Symbolic addressing has priority and Absolute addressing has priority. The choice affects how UDT member changes propagate through the program and through external consumers such as HMI panels.
| Mode | Behavior on UDT Edit | Best Use |
|---|---|---|
| Symbolic priority | Symbolic names track the UDT. Absolute addresses are recomputed on every compile. HMI tags bound symbolically follow the rename automatically. | New projects; programs with extensive HMI integration; OPC UA exposure. |
| Absolute priority | Absolute addresses are pinned at first compile. Renaming a UDT member leaves the absolute address unchanged, which can cause silent aliasing where two symbolic names point at the same byte. | Legacy migration from STEP 7 V5; programs that use direct PEW / PAW access patterns from external tooling. |
If the project is in Absolute addressing has priority mode, switching to Symbolic addressing has priority before performing the UDT edit produces a more deterministic recovery. The change is in the CPU properties under General > Addressing mode; after switching, perform the UDT modification and then the project-wide compile. The trade-off is that the symbolic binding becomes the source of truth: any external system that reads the absolute address (a third-party SCADA, a legacy HMI panel that consumes DBs by raw address) must be rebound to the new offsets.
L, T, DB, and DI access in the compiled code. For large programs the recompile can take many minutes. Plan the switch during a scheduled downtime window.
Special Cases
Function block multi-instances
When a UDT is used as the static section of an FB that is itself instantiated as a multi-instance in a higher-level FB, the declaration update must be propagated through both levels. After updating the lower-level FB, open the higher-level FB and update its static section explicitly. TIA Portal does not always cascade the reconciliation across nested multi-instances in a single compile.
PLC data type versioning in V15 and later
TIA Portal V15 introduced a type-version fingerprint that tracks the structure of every PLC data type. If a project is opened in a newer TIA Portal version and the same UDT is opened, even without intentional edits, the type fingerprint can change because the editor normalizes whitespace, comment formatting, or attribute storage. The cure is identical - recompile - but the root cause is a non-functional change and should be understood when diagnosing a UDT inconsistency that appears after a TIA Portal version upgrade.
Library UDTs
UDTs that are managed as master copies in a project library and re-used across multiple stations can be edited in the library and propagated to consumers. The consumer project must be recompiled after the library update; the consumer's instance declarations are reconciled by the same project-wide compile pass. If the consumer project does not recompile, the type fingerprint stored in the consumer does not match the master and the consumer blocks are flagged as inconsistent on the next open.
UDT used as a function block parameter
If a UDT is used as the type of an FB InOut parameter, the actual parameter passed at the call site must also be re-checked. TIA Portal flags the call site with a "Type mismatch" error if the actual parameter is a UDT instance whose structure has shifted. Update the actual parameter declaration (it is usually a DB variable) and recompile. The same applies to Input and Output parameters of FBs called from SCL REGION blocks that pass the UDT by value.
Memory Layout and Address Offset Implications
Adding, removing, or reordering members in the middle of a UDT changes the byte offset of every member that follows. For a DB that contains an array of UDT instances, the stride of the array also changes, which affects every absolute address into the array.
Example: a UDT typeValve originally contains members at the following offsets within the UDT footprint:
| Offset (byte) | Member | Type |
|---|---|---|
| 0.0 | cmdOpen |
BOOL |
| 2.0 | cmdClose |
BOOL |
| 4.0 | flowSetpoint |
REAL |
| 8.0 | flowActual |
REAL |
| 12.0 | statusWord |
WORD |
| 14.0 | alarmWord |
WORD |
If a new DINT member cycleCounter is inserted between cmdClose and flowSetpoint, the offsets of all subsequent members shift by 4 bytes. A global DB containing valveBank : ARRAY[1..32] OF "typeValve" sees every flowSetpoint, flowActual, statusWord, and alarmWord address change across the entire array. The total DB length grows by 32 × 4 = 128 bytes, which on a CPU with a tight work-memory limit can push the DB past the configured maximum size.
The consequences in the wider system:
- HMI tags bound by absolute address to any shifted member must be re-bound. With symbolic priority, the rebind is automatic. With absolute priority, the HMI keeps reading from the old address and now returns the value of a different member - a particularly dangerous condition in a safety-relevant application.
- OPC UA nodes exposed by an S7-1500 OPC UA server are bound symbolically and follow the rename automatically. Verify the OPC UA server configuration in the CPU properties after the recompile and confirm that the namespace regeneration produced the expected member list.
-
Cross-CPU communication using
GET/PUTinstructions on S7-1500 orBSEND/BRCVon S7-1200 with absolute addressing must be reviewed against the new offsets before the partner CPU is downloaded. - Retained tags in the affected DB may be written to a new offset on the next download. If the process depends on the retained values surviving the UDT edit, do a cold restart rather than a warm restart after the download, or set the UDT members to non-retained in the type definition and reinitialize the values from the program on first scan.
Best Practices for UDT Design
The UDT is the most expensive structure to refactor in a mature TIA Portal program. The following practices prevent the inconsistency condition from arising in the first place and keep the UDT refactor path short when it does.
- Plan the UDT structure before the first instance. Document every member, its data type, its range, its unit, and its HMI binding. Treat the first commit of the UDT as a contract; any later change is a breaking change.
- Append, never insert. Add new members only at the end of the UDT. This preserves the byte offset of every existing member and lets the project-wide compile resolve the new member with no other impact.
- Use symbolic addressing as the default. Switch the project to Symbolic addressing has priority in the CPU properties. The cost is a one-time recompile; the benefit is that HMI tags, OPC UA nodes, and any other symbolic consumer follow the UDT automatically.
- Manage UDTs in a project library. Master copies of the UDT in a global library provide a single source of truth, version history, and a controlled distribution path to multiple stations.
-
Reserve a member block at the end of every UDT. A trailing array of 16 or 32
WORDorDWORDmembers reserved for future use lets the engineer add small ad-hoc values without touching the UDT definition. Name the membersreserve_0throughreserve_15and document the intent in the comment column. When a new field is required, rename one of the reserved members to its final name and document the change. -
Version the UDT in the name. Use a suffix such as
_v1,_v2when making a breaking change. Mark the previous UDT as deprecated by leaving it in the project but removing it from the library; new code references the new UDT, old code continues to work until it is refactored. - Compile after every UDT change. Never leave an inconsistent declaration in the project tree. A "Compile all" pass at the end of every editing session catches inconsistencies before they cascade.
- Use PLC data type attributes for HMI visibility, OPC UA exposure, and motion control binding. TIA Portal reads the attributes at compile time and uses them to configure the consumer. Editing the UDT member data type invalidates the attribute; recompile restores the binding.
- Document UDT members. Use the comment column in the UDT declaration for every member. A member without a comment is the first candidate for a wrong default value or a wrong scaling factor when the program is handed over to the next engineer.
Verification
After applying any of the three resolution methods, verify that the project is consistent and the runtime behaviour matches the offline project.
- Project consistency. Right-click the CPU and select Compile > Software (rebuild all blocks). The compile output must end with "0 errors, 0 warnings" (warnings about library updates can be acknowledged). Any residual error is a code-level reference to a removed or renamed UDT member and must be fixed by hand in the affected network.
- Block consistency in online mode. Go online with the CPU. In the project tree, the online and offline blocks should be identical. If the offline block carries a timestamp later than the online block, the project has not been downloaded yet; perform a controlled download.
- Symbolic vs absolute comparison. In a representative DB, open the declaration view and the "Monitor / Modify" view side by side. Verify that the symbolic member names map to the expected byte offsets by hovering the cursor over a tag and reading the absolute address shown in the tooltip.
- HMI tag binding integrity. On a sample of HMI tags that bind to the modified DB, force a value change in the PLC and confirm that the HMI display updates. In a system with OPC UA exposure, browse the OPC UA namespace and confirm that the modified UDT members are present and have the expected data types.
- Retained value preservation. If the UDT edit shifts retained members, perform a controlled power cycle. After restart, compare the live values to the values recorded before the download. A delta in any shifted member confirms that the offset moved; restore the value by re-initialization or accept the loss if the process is designed to start from a known state.
- Library consumers. If the UDT is distributed via a project library, open a consumer project and confirm that the library update is offered and that the consumer's project-wide compile passes.
Troubleshooting Matrix
| Symptom | Likely Cause | Fix |
|---|---|---|
| DB will not open; "Declaration inconsistent" dialog | UDT modified; instance not reconciled | Per-block Update declaration |
| "Type conflict" on FB Input/Output parameter | UDT used as FB parameter type; call site not updated | Open FB, recompile; update actual parameter |
| HMI shows old values after UDT edit | Absolute addressing priority; HMI bound to shifted address | Switch to symbolic priority, or re-bind HMI tag |
| Compile error references a UDT that does not appear in the project tree | Library UDT update not propagated to consumer | Update library in consumer, recompile |
| Compile error "Type version mismatch" | TIA Portal version changed; type fingerprint differs from stored | Project-wide compile all |
| Retained values corrupted after download | UDT member offsets shifted; warm restart preserved old addresses | Cold restart; re-initialize from program |
| Multi-instance FB not updated | Nested multi-instance declaration not cascaded | Open parent FB, manual Update declaration |
| OPC UA namespace missing new UDT members | OPC UA server not recompiled with the new UDT | Recompile PLC; CPU pushes new server config on next run |
| Compile succeeds but HMI loses tag connection | HMI panel uses absolute address in Absolute priority mode | Switch project to Symbolic priority and re-download both PLC and HMI |
| UDT in FB static section flagged but no DB error | FB not recompiled after UDT change | Open FB, right-click static section, Update declaration, recompile |
FAQ
Why does TIA Portal refuse to open a DB after I edit a UDT?
TIA Portal stores a type fingerprint on every UDT instance. Editing the UDT invalidates the fingerprint of every block that references it, and the editor refuses to open the block until the declaration is reconciled. Use the per-block Update declaration command or the project-wide Compile all pass to clear the inconsistency.
Can I prevent the offset shift when adding a new UDT member?
Yes - always append the new member at the end of the UDT. Inserting in the middle shifts every downstream offset and breaks any HMI tag, OPC UA node, or cross-CPU communication bound by absolute address. If the new member must logically sit in the middle, use a reserved block at the end of the UDT to hold the value and add a symbolic name in the comment column.
Does "Compile all" always resolve UDT declaration errors?
No. Project-wide Compile all reconciles the declaration automatically in most cases (empirically 50-60% of instances) but does not fix code that references renamed or removed UDT members in FBs. Those errors must be fixed by hand in the affected network by updating the member access to the new name or by adapting the algorithm to the new structure.
Which addressing mode should I use when working with UDTs?
Use Symbolic addressing has priority for new projects and for any project that exposes UDT members to HMI, OPC UA, or another CPU. Symbolic priority makes the symbolic name the source of truth and re-derives the absolute address on every compile, so a UDT edit propagates automatically. Absolute priority is appropriate for legacy migrations from STEP 7 V5 where many external consumers depend on pinned absolute addresses.
Will editing a UDT in a library propagate to all consumer projects?
Yes, but only after the consumer project is opened and the library is updated. After the library update, the consumer's project-wide Compile all must be run to reconcile every block that references the updated UDT. Consumers that are not recompiled carry a stale type fingerprint and are flagged as inconsistent on the next open.
What is the safest way to add a new tag to a heavily used UDT?
Use the reserve block approach. Reserve a block of WORD or DWORD members at the end of the UDT when it is first designed. When a new tag is required, rename one of the reserved members to its final symbolic name and update the consumer program and HMI bindings. The byte offsets of all earlier members are preserved and the rest of the program is untouched.