Resolving String Copy Error on S7-1200 with TIA Portal V13

David Krause11 min read
S7-1200SiemensTroubleshooting
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

Problem Overview

The symptom is a runtime String processing error raised by an S7-1200 CPU 1214C (firmware 4.1) when a user attempts to copy one SCL STRING variable to another. The naïve assignment

String2 := String1;

with both tags declared at a length of 20 bytes consistently faults. The same fault occurs with

String2 := LEFT(IN := String1, L := 20);

where String2 remains empty on every scan. The defect is observable on TIA Portal V13 SP1 Update 9 with the matching S7-1200 system image; it is not a CPU hardware failure and is recoverable with corrected SCL syntax and tag declarations.

Affected Versions and Tooling

Component Version Confirmed Notes
STEP 7 / TIA Portal V13 SP1 Update 9 Project engineering environment
S7-1200 CPU CPU 1214C DC/DC/DC and DC/DC/RLY Tested hardware
CPU Firmware FW 4.1 Released with TIA V13 SP1; ships with STRING 254-byte maximum
Programming Language SCL (Structured Control Language) Issue is syntax/declaration driven, not STL or LAD
String Length Tested 20 bytes Inside 0..254 byte range

Firmware 4.x on the S7-1200 line is the first generation to include the optimized block interface and full STRING support. The error presents regardless of whether the optimized block attribute is enabled or disabled, but the declaration location of the variables (local temp, local static, or global DB) is the controlling factor.

Root Cause Analysis

The String processing error on the S7-1200 is the runtime diagnostic emitted when the firmware detects an inconsistency in the STRING header. Every S7 STRING is a compound of two header words followed by a character array:

  • Word 0 (Bytes 0..1): Maximum length in characters (e.g. 254)
  • Word 2 (Bytes 2..3): Current (actual) length in characters
  • Bytes 4..257: Character payload (ASCII)

An SCL assignment A := B for STRING types is valid only when both operands are fully qualified, declared symbols with the same maximum length. Three conditions each independently trigger the fault observed in the report:

  1. Unqualified tag references. The bare names String1 and String2 are not resolvable as global symbols; the SCL compiler will accept them only as local tags (with the # prefix in TIA V13 onward) or as fully qualified DB members (with the "DB_name". prefix).
  2. Uninitialized temporary strings. If the destination String2 is a TEMP variable, the STRING header on entry to the block contains whatever pattern is on the stack. The runtime check actual_length <= max_length fails and the CPU raises String processing error before the assignment proceeds.
  3. Length-mismatch propagation from LEFT. The LEFT standard function returns a STRING whose actual length is set to the L input; if the receiving variable has a smaller maximum length than the caller's expected, the same header check trips. LEFT returning an empty string in the field report indicates the destination was never written — the fault was raised and execution aborted before the copy.
Note: TIA Portal V13 SP1 introduced strict name resolution for block-local and instance-local tags. Bare names without # or DB-qualifier that worked in V11/V12 will compile but fail at download or in the first scan on V13+ targets. Always re-validate legacy SCL blocks after a TIA upgrade.

String Data Type Specification (S7-1200)

Property Value
Keyword STRING[ n ] where 0 ≤ n ≤ 254
Total memory footprint n + 2 bytes for header + 2 bytes for max length = n + 4 bytes
Default initialization (in DB) Empty string (actual length = 0, all character bytes = 16#00)
Default initialization (TEMP, STATIC) Undefined — must be initialized explicitly
Wide character variant WSTRING — UCS-2, header = 4 + 2*length bytes
Access via AT view Yes; declare AT overlay on a byte array of size n+4

For the 20-byte strings in the source report, each instance occupies 24 bytes (2 bytes max + 2 bytes current + 20 bytes payload). All SCL STRING operators — :=, LEFT, RIGHT, MID, CONCAT, DELETE, INSERT, REPLACE, FIND, LEN — read and rewrite the 4-byte header. Any operator invoked on an uninitialized TEMP string can fault.

Fix 1 — Use Fully Qualified DB Tag Names

Declare both strings as global symbols inside a global data block. This is the recommended pattern for cross-block or HMI-visible strings on S7-1200.

  1. Open the project tree in TIA Portal and add a new Data Block (DB), e.g. Data_block_10.
  2. Inside Data_block_10 add two static tags:
    
    String1 : STRING[20];   // 24 bytes total
    String2 : STRING[20];   // 24 bytes total
    
  3. Disable the Optimized block access attribute on the DB if any external (non-S7-1200) client accesses the absolute addresses — otherwise leave it enabled, the STRING operator set is identical.
  4. In the SCL source, write the assignment with the full DB qualifier:
    
    "Data_block_10".String2 := "Data_block_10".String1;
    
  5. Compile (Ctrl+B) and download. The PLC should now copy the entire 20-character payload in one scan without raising the error.

If the SCL block does not accept the literal "Data_block_10" it means the DB has not been added to the block's interface. Right-click the block in the project tree → Properties → Interfaces and confirm the DB appears under Used Blocks, or use a multi-instance call where the DB is the instance itself.

Fix 2 — Local Tags in a Function (FC) or Function Block (FB)

When both strings live inside a single SCL block, the correct SCL syntax uses the # prefix introduced in TIA V11 and tightened in V13 SP1:


FUNCTION_BLOCK "FB_String_Copy"
VAR
    String1 : STRING[20];   // STATIC — retained between scans
    String2 : STRING[20];   // STATIC
END_VAR

BEGIN
    #String2 := #String1;
END_FUNCTION_BLOCK

Rules for the # prefix:

  • # is required for all block-local tags (TEMP, STATIC, CONSTANT, IN, OUT, IN_OUT) inside the interface.
  • # is forbidden for global DB members — use "DB_name".Member instead.
  • Constants are read with the literal, e.g. String2 := 'X'; for a 1-char string.
Warning: TIA Portal V13 SP1 will emit warning "Identifier is not unique" if the block contains both a local tag String1 and a global tag of the same name. Rename one of them to avoid the warning, which can mask the runtime fault if disabled.

Fix 3 — Initialize Temporary Strings First

The original post's recommendation to write string2 := 'X'; before the bulk copy is a valid workaround for TEMP variables. The full pattern:


FUNCTION "FC_String_Copy" : Void
VAR_TEMP
    String1 : STRING[20];
    String2 : STRING[20];
END_VAR
BEGIN
    // Initialize headers to prevent undefined-length faults
    #String1 := '';          // max=20, actual=0, payload cleared
    #String2 := '';

    #String1 := 'Hello S7-1200!';
    #String2 := #String1;    // safe copy
END_FUNCTION

The empty-string literal '' sets the current length to 0 and zeroes the character array. After that, any subsequent SCL string operator sees a consistent header and the firmware will not raise String processing error.

Fix 4 — Correct Use of the LEFT Standard Function

LEFT returns a STRING. To capture the result, the destination tag must be large enough to hold the requested length, and the call must use a fully qualified source:


"Data_block_10".String2 := LEFT(
    IN := "Data_block_10".String1,
    L  := 20
);

Common pitfalls:

  • L larger than IN — returns the entire string, no error.
  • L = 0 — returns an empty string; destination remains unchanged (a common reason String2 "stays empty" in the field report when L was inadvertently set to 0).
  • Mixing STRING and WSTRING — SCL will not implicitly convert; use the STRING_TO_WSTRING and WSTRING_TO_STRING converters in the CONVERT block group.

Alternative Copy Methods

Method SCL Statement Use When
Direct assignment #dst := #src; Same block, both fully qualified.
DB-to-DB assignment "DB_A".s2 := "DB_B".s1; Cross-block copy, same max length.
Slice via AT view #dst AT view of ARRAY OF BYTE := #src AT view of ARRAY OF BYTE; Bulk-byte copy; bypasses header checks — only for advanced users.
Concat trick #dst := CONCAT(IN1 := '', IN2 := #src); Forces header rewrite; helpful when header is suspected corrupt.
MOVE_BLK Use the MOVE (DWORD) or BLKMOV (SFC 20) on the full 24 bytes Performance-critical loops; not type-safe.
IEC standard STRING_TO_... converters #dst := STRING_TO_CHAR(IN := #src); Legacy compatibility for non-SCL blocks.

The CONCAT with empty string trick is worth keeping in the toolbox: it explicitly writes a fresh header (max length = 254 by default, but constrained by destination) and is a one-line sanity test when chasing header corruption on legacy projects.

Runtime Error Codes and Diagnostics

Diagnostic Buffer Entry Meaning Likely Cause
String processing error (no detailed code) Header inconsistency Uninitialized TEMP string; max length of source > max length of destination; or operator on a constant.
Area length error when reading Source outside valid memory String tag points to a deleted DB; check Cross-references in TIA.
Area length error when writing Destination too small Source has actual length > destination max length; resize destination or truncate with LEFT.
OB not loaded / OB 121 raised CPU tried to call a non-existent error OB Programming error OB not present; CPU goes to STOP.

The S7-1200 firmware will only invoke the user's Programming error OB (OB 121) if it has been generated and downloaded. Without OB 121, the CPU transitions to STOP on the first String processing error and writes the diagnostic event "String processing error in FC/FB n, area: ..." to the diagnostic buffer.

Verification Procedure

  1. Online → Go online with the CPU; confirm the active program matches the compiled project (no download differences in the Compare editor).
  2. Open the watch table that contains the source and destination strings; force the source to a known value, e.g. 'TEST_1234567890ABCDE'.
  3. Trigger the SCL block once (set EN input or call via cyclic task). Confirm the destination reflects the source byte-for-byte, including the actual length in the Monitor value pane.
  4. Inspect Online & diagnostics → Diagnostics buffer; there should be no String processing error entries after the corrected code is in place.
  5. Repeat the watch-table test with the SCL editor in monitor mode, then set a breakpoint on the assignment line; verify the assignment executes without the LED pattern indicating a STOP transition (STOP/RUN LED solid green during the test).
  6. Cycle power to the CPU; if the strings are STATIC or DB-global, values persist; if they are TEMP, they reset to empty after the next cold restart, which is expected.

Common Pitfalls and Field Tips

  • Mixing STRING and WSTRING. WSTRING is 16-bit UCS-2; assignments between the two require explicit conversion. The SCL compiler will reject implicit conversion with a type-mismatch error, but a runtime String processing error can occur if the conversion is attempted via CHAR_TO_... with insufficient buffer.
  • Watch the second header word. If a string's actual length ever exceeds its max length, every subsequent operator faults. Use the Monitor pane to display both header words when debugging legacy code.
  • HMI aliasing. An HMI tag pointing at a STRING DB member with a length override larger than the DB's max length will write past the end of the DB; the SCL block then reads a corrupt header on the next scan.
  • Retentivity. TIA V13 SP1 honors the Retain attribute for STRING variables. A retained string survives a warm restart but its actual length is part of the retained image — verify that the destination DB's retentivity settings match between HMI, PLC, and the loaded project.
  • Compiler version drift. A block compiled in TIA V13 SP1 is forward-compatible to V14/V15 but the V13 STRING operator set is more limited; if copying logic is added later, re-compile under the current TIA version.

Troubleshooting Matrix

Symptom Likely Cause First Action
CPU goes to STOP, String processing error in buffer Uninitialized TEMP or length mismatch Initialize with #s := '';; verify max lengths equal
Destination stays empty after LEFT call L = 0 or uninitialized source Inspect L value in watch table; check source actual length
Compiler error Unknown identifier 'String1' Bare name without # or DB prefix Add # for local or "DB_name". for global
Compiler accepts, runtime faults only on first cycle TEMP not initialized Use STATIC instead, or pre-assign empty string
Watch table shows wrong character count Header corruption from a previous, larger write Re-initialize the string in OB100 / startup

Reference Links

FAQ

Why does my S7-1200 raise "String processing error" on a simple SCL assignment?

The fault is raised when the STRING header (max length + actual length + payload) is inconsistent. The most common cause on TIA V13 SP1 is an uninitialized temporary string or a bare-name tag reference that the compiler cannot resolve. Initialize the destination with #s := ''; and qualify the source with # or "DB_name"..

Do I have to use the # prefix for local variables in TIA Portal V13 SP1?

Yes. TIA V11 introduced the # prefix for block-local symbols and TIA V13 SP1 tightened the check. Omitting the prefix for a TEMP or STATIC tag will compile with a warning on legacy firmware but the runtime may STOP on firmware 4.x. Use #tagname inside FCs/FBs and "DB_name".tagname for global DB members.

Why does LEFT leave my destination string empty?

LEFT returns a STRING with the actual length set to the L input. If L is 0, the result is an empty string and the destination is effectively cleared. Verify L in the watch table and ensure the destination is a fully qualified symbol with a max length ≥ L.

Can I mix STRING and WSTRING in the same assignment?

No. SCL does not implicitly convert between 8-bit STRING and 16-bit WSTRING. Use the standard converters STRING_TO_WSTRING and WSTRING_TO_STRING from the CONVERT library, and ensure the destination has sufficient capacity for the wider encoding.

What is the maximum STRING length on a CPU 1214C firmware 4.1?

254 characters. Each STRING[n] occupies n + 4 bytes of memory. For the 20-byte strings in this case report, each instance is 24 bytes. Firmware 4.1 supports STRING and WSTRING with the same operator set used in TIA V13 SP1.

Back to blog