diff --git a/bin/slurm_calibrate.sh b/bin/slurm_calibrate.sh
index 4cfa4484a88c8fd36919325616df74458ef51856..d1baf806b1bd531e47366892118e5226037b496a 100755
--- a/bin/slurm_calibrate.sh
+++ b/bin/slurm_calibrate.sh
@@ -33,6 +33,9 @@ module load texlive/2019
 # make sure we use agg backend
 export MPLBACKEND=AGG
 
+# Ensure Python uses UTF-8 for files by default
+export LANG=en_US.UTF-8
+
 # start an ip cluster if requested
 if [ "${ipcluster_profile}" != "NO_CLUSTER" ]
 then
diff --git a/src/xfel_calibrate/calibrate.py b/src/xfel_calibrate/calibrate.py
index 4bc573bea5ac2807dcdfa5cb91a3ab94b558cfcf..17e4aa0ca81776f63bf7ef53cb8ae0e46c689b24 100755
--- a/src/xfel_calibrate/calibrate.py
+++ b/src/xfel_calibrate/calibrate.py
@@ -3,6 +3,7 @@
 import argparse
 import ast
 import inspect
+import locale
 import math
 import os
 import pprint
@@ -859,6 +860,9 @@ def make_pipeline_yaml(parms, version, report_path, output_dir):
 
 def run():
     """ Run a calibration task with parser arguments """
+    # Ensure files are opened as UTF-8 by default, regardless of environment.
+    locale.setlocale(locale.LC_CTYPE, ('en_US', 'UTF-8'))
+
     parser = make_extended_parser()
     args = deconsolize_args(vars(parser.parse_args()))
     detector = args["detector"].upper()
diff --git a/webservice/webservice.py b/webservice/webservice.py
index 991acbf3d92b0ebe1ef3d46a22ecc639a4c4b0fb..75be746f29d562cc57609a7bc455b839979f6e09 100644
--- a/webservice/webservice.py
+++ b/webservice/webservice.py
@@ -6,6 +6,7 @@ import getpass
 import glob
 import inspect
 import json
+import locale
 import logging
 import os
 import sqlite3
@@ -1198,6 +1199,9 @@ def main(argv: Optional[List[str]] = None):
     if argv is None:
         argv = sys.argv[1:]
 
+    # Ensure files are opened as UTF-8 by default, regardless of environment.
+    locale.setlocale(locale.LC_CTYPE, ('en_US', 'UTF-8'))
+
     parser = argparse.ArgumentParser(
         description='Start the calibration webservice'
     )