ConfigParser Rejects a Percent Sign: Choose Literal or Interpolated Values
By ON Lab · Sources checked November 9, 2026
Decide whether percent signs are literal data or interpolation syntax. Test retrieval, not just reading the file; the failure can appear only when a value is requested.
Reproduce the boundary in a disposable example
An INI value containing a percent sign fails when retrieved or assigned.
import configparser
text = "[display]\nlabel = 75% complete\n"
config = configparser.ConfigParser()
config.read_string(text)
try:
config.get("display", "label")
except configparser.InterpolationSyntaxError:
pass
else:
raise AssertionError("expected interpolation failure")
assert config.get("display", "label", raw=True) == "75% complete"
literal = configparser.ConfigParser(interpolation=None)
literal.read_string(text)
assert literal["display"]["label"] == "75% complete"
escaped = configparser.ConfigParser()
escaped.read_string("[display]\nlabel = 75%% complete\n")
assert escaped["display"]["label"] == "75% complete"
print("three retrieval contracts verified")Read the result before changing application code
Reading succeeds in the first case, so treating this as a missing-file error sends diagnosis in the wrong direction. The raw read isolates stored text from interpolation. Keep a small copy of the failing section, with secrets removed, and compare the retrieved value byte for byte.
Choose the behavior your caller needs
Use a raw read for one literal lookup, disable interpolation for a file whose whole schema is literal, or escape percent signs when you control a file that intentionally retains basic interpolation. Disabling interpolation can leave existing placeholder references unresolved. Verify every dependent setting before changing that parser-wide choice. Do not blindly double percent signs inside values supplied by unrelated formats.
Scope and limits
This covers basic ConfigParser interpolation. ExtendedInterpolation uses a different placeholder syntax; logging formatting and URL percent encoding are separate systems.
Related: compare the adjacent data or execution boundary.
The embedded example was executed in an isolated local Python process on November 9, 2026. It is a reproducible boundary check, not a test of your full application.