Resolving Ignition Script File Path Backslash Errors

Erik Lindqvist6 min read
Other ManufacturerOther TopicTroubleshooting
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 path \\machine\c$\Logs\03_filename.log fails in an Ignition script because the Jython parser turns \03 into a single control character (code point 3) before open() sees the string. The error text shows it as \x03_filename.log. A file named 31_filename.log shows \x19 for the same reason. The file system never gets the name you typed.

Quote swaps, string splits and file renames that leave the path broken

Three changes get tried first for this symptom. None of them fixes the path, and one of them hides the fault.

Attempted fix Result Why it fails
Switch between single and double quotes Same \x03 error Python treats '...' and "..." the same way. Both decode escape sequences.
Insert a quote after Logs \x disappears, but so does the backslash (Logs03_filename.log) \' is also an escape sequence. It consumes the backslash and produces a literal quote.
Split the path and concatenate the pieces Original error, or stray spaces Any fragment that still contains \0–\7 gets decoded when that fragment is parsed. Joining the pieces afterwards changes nothing.
Rename the file without the numeric prefix File opens The digits are removed, so no octal escape forms. The next file whose name starts with n, t, r, f, a, b, v or x breaks again.

Backslash escape decoding in Jython string literals

Ignition runs scripts in Jython, which follows Python 2 string-literal rules. A backslash followed by 1–3 octal digits (0–7) is replaced by one character whose value is that octal number. The quantity that decides the case is the length of the decoded string. \03 is three typed characters but becomes one character at runtime. The count shrinks before any file I/O happens.

Fragment after Logs Decoded as Value Effect on the path
\x + non-hex invalid escape n/a Script fails to compile
\m, \c, \L not an escape unchanged Backslash kept, which is why the rest of the path looked correct

A leading \\ is also an escape. It collapses to one backslash, so a UNC path typed with two leading backslashes reaches the OS with one. That is a relative path, not a network share.

Every day-of-month prefix from 01 to 31 produces an octal escape or a null. A daily log file will fail on every day of the month, not only on specific days.

Diagnosing the decoded path with repr() and os.path

This error has two possible causes, and they are separate problems:

  • Literal fault: the string itself is corrupted by escape decoding.
  • Access fault: the path is correct, but the host running the script cannot reach it.

Run these checks in the Script Console to tell them apart:

  1. Print repr(filepath). Any \x.., \t, \n or \x00 in the output confirms a literal fault.
  2. Print len(filepath) and compare it with the number of characters you intended. A shorter count confirms decoding ate characters.
  3. Print os.path.exists(filepath). It returns False for both faults. Only read it after step 1 shows a clean string.
  4. If repr() is clean and exists() is still False, the problem is an access fault: share name, permissions or network reachability.
import os
filepath = '\\machine\c$\Logs\03_filename.log'
print repr(filepath)
print len(filepath)
print os.path.exists(filepath)

Path-building procedure for UNC admin shares

Three literal forms deliver the path intact. Doubling the backslashes and switching to forward slashes have both been confirmed to open the file on this installation.

# Option 1: escape every backslash (four leading for UNC)
filepath = '\\\\machine\\c$\\Logs\\03_filename.log'

# Option 2: forward slashes; the Java file layer maps them on Windows
filepath = '//machine/c$/Logs/03_filename.log'

# Option 3: raw string; backslashes are not decoded
filepath = r'\\machine\c$\Logs\03_filename.log'

When the day prefix is generated at runtime, keep the base path as a raw string and join the parts with os.path. That way no literal ever contains a backslash followed by a digit:

  1. Define the share root once as a raw string or with forward slashes.
  2. Build the filename from a formatted date, for example datetime.now().strftime('%d'), which gives the zero-padded day.
  3. Combine the root and filename with os.path.join() instead of typing separators by hand.
  4. Open the file in a with block so the handle closes even if the read throws.
import os
from datetime import datetime

base = r'\\machine\c$\Logs'
name = datetime.now().strftime('%d') + '_filename.log'
filepath = os.path.join(base, name)

print repr(filepath)
with open(filepath) as f:
    data = f.read()

Confirming the file opens from the correct execution scope

A clean repr() and a successful open() in the Script Console prove only that the Designer workstation can reach the share. Ignition runs scripts on different hosts depending on where they are defined:

  • Script Console and Designer scripts run on the engineer's PC under the engineer's Windows account.
  • Vision client scripts run on the client PC.
  • Gateway event scripts, timer scripts and tag change scripts run on the gateway server, under the account the Ignition service uses.

To verify each scope:

  1. Run the diagnostic block in the Script Console. Confirm repr() is clean and exists() returns True.
  2. Put the same block in the scope that will run in production, such as a gateway timer script. Send the repr() and exists() output to the gateway logger instead of print.
  3. Check the gateway log. If the Console passed but the gateway returns False, the Ignition service account has no rights to the c$ admin share on the target machine.
  4. Run the script on the first and the last day of the month, or feed the prefix values 01–31 in directly. This confirms that no date-generated name reintroduces an escape.

Recurring path pitfalls in Ignition scripts

  • Raw string ending in a backslash. r'\\machine\c$\Logs\' does not compile, because the final backslash escapes the closing quote. Leave off the trailing separator and let os.path.join() add it.
  • Paths copied from Windows Explorer. Pasting a path straight into a normal string literal carries every escape hazard in the table above. Paste it into a raw string instead.
  • Paths stored in tags or database rows. Values read at runtime are not decoded, so single backslashes are correct there. Doubling them in the tag gives \\ in the actual path.
  • Admin shares. c$ needs local administrator rights on the target PC. A dedicated share with read permission for the gateway service account is easier to keep running than an admin share.
  • Unhandled I/O exceptions in gateway scripts. A missing file on a new day, before the log has been created, can throw repeatedly. Wrap the open() call and log the repr() of the path when it fails.

FAQ

What happens if an Ignition file path contains \n or \t?

Jython replaces \n\tA folder such as\new or \temp then no longer matches any file-system name. Use a raw string, doubled backslashes or forward slashes.

What happens if I use forward slashes for a Windows UNC path in Ignition?

It works. '//machine/c$/Logs/03_filename.log' contains no escape sequences, and the Java file layer under Jython resolves forward slashes on Windows, including UNC paths.

What happens if a raw string file path ends with a backslash?

The script fails to compile, because the final backslash escapes the closing quote even in a raw string. Leave off the trailing separator and build the full path with os.path.join().

What happens if the path works in the Script Console but not in a gateway script?

The string is correct, but the gateway service account cannot reach the share. The Console runs under your Windows login; gateway scripts run under the Ignition service account on the server. Grant that account read access to the share, or use a non-admin share.

When should I contact Inductive Automation support about a file access error?

Contact official support once repr() shows a clean path, os.path.exists() returns True on the gateway host, and open() still fails from gateway scope. Include the full exception, the gateway log excerpt and the Ignition version.

Back to blog