diff --git a/porthole/queries.py b/porthole/queries.py
index 3dfded4..943dc0f 100644
--- a/porthole/queries.py
+++ b/porthole/queries.py
@@ -59,6 +59,8 @@ class RowDict(OrderedDict):
     def __init__(self, data=None, fields=None, values=None):
         fields_and_values_provided = fields is not None and values is not None
         if fields_and_values_provided is True and data is None:
+            if len(fields) > len(set(fields)):
+                raise ValueError("Field names must be unique, but your result set contains non-unique field names.")
             data = OrderedDict(zip(fields, values))
         else:
             data = data or OrderedDict()

Raise Error if QueryResult contains duplicate keys
QueryResult will have unexpected behavior if the query has returned a result with duplicate keys (blank columns written to Excel, etc.)

The query should raise an error at some stage so that the user is forced to fix this.
diff --git a/tests/test_Queries.py b/tests/test_Queries.py
index 8ae1be1..f65c4c0 100644
--- a/tests/test_Queries.py
+++ b/tests/test_Queries.py
@@ -104,6 +104,18 @@ class TestRowDict(unittest.TestCase):
         self.assertIn('Bar', test_row.values())
         self.assertEqual(headers + ['Foo'], list(test_row.keys()))
 
+    def test_unique_field_name_constraint(self):
+        with self.assertRaises(ValueError):
+            RowDict(
+                fields=['A', 'A'],
+                values=[[1, 2]]
+            )
+        with self.assertRaises(ValueError):
+            RowDict(
+                fields=['A', 'B', 'A'],
+                values=[[1, 2, 3]]
+            )
+
 
 headers = ['Name', 'DOB']
 row1 = ['Billy', date(1988, 4, 24)]

environment.yml
pip install -e .
parse_log_pytest
environment.yml
pytest
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
cffi @ file:///home/conda/feedstock_root/build_artifacts/cffi_1631636256886/work
click==8.0.4
cryptography @ file:///tmp/build/80754af9/cryptography_1635366128178/work
dataclasses==0.8
dominate==2.9.1
Flask==0.12.2
Flask-Bootstrap==3.3.7.1
Flask-WTF==0.14.2
greenlet @ file:///tmp/build/80754af9/greenlet_1628879730431/work
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig==1.1.1
itsdangerous==2.0.1
Jinja2==3.0.3
MarkupSafe==2.0.1
packaging==21.3
pluggy==1.0.0
-e git+https://github.com/speedyturkey/porthole.git@20bc80bc19641a1071563f8d59fd3ba135fd31bb#egg=porthole
psycopg2 @ file:///tmp/build/80754af9/psycopg2_1612298609104/work
py==1.11.0
pycparser @ file:///tmp/build/80754af9/pycparser_1636541352034/work
PyMySQL @ file:///tmp/build/80754af9/pymysql_1610482411930/work
pyparsing==3.1.4
pytest==7.0.1
SQLAlchemy @ file:///tmp/build/80754af9/sqlalchemy_1626948432260/work
tomli==1.2.3
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
visitor==0.1.3
Werkzeug==2.0.3
WTForms==3.0.0
XlsxWriter @ file:///opt/conda/conda-bld/xlsxwriter_1649073856329/work
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: porthole
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - cffi=1.14.6=py36hd8eec40_1
  - cryptography=35.0.0=py36hd23ed53_0
  - greenlet=1.1.1=py36h295c915_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - krb5=1.20.1=h568e23c_1
  - ld_impl_linux-64=2.40=h12ee557_0
  - libedit=3.1.20230828=h5eee18b_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libpq=12.15=h37d81fd_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - psycopg2=2.8.6=py36h3c74f83_1
  - pycparser=2.21=pyhd3eb1b0_0
  - pymysql=1.0.2=py36h06a4308_1
  - python=3.6.13=hb7a2778_2_cpython
  - python_abi=3.6=2_cp36m
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlalchemy=1.4.22=py36h7f8727e_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xlsxwriter=3.0.3=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - click==8.0.4
      - dataclasses==0.8
      - dominate==2.9.1
      - flask==0.12.2
      - flask-bootstrap==3.3.7.1
      - flask-wtf==0.14.2
      - iniconfig==1.1.1
      - itsdangerous==2.0.1
      - jinja2==3.0.3
      - markupsafe==2.0.1
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - tomli==1.2.3
      - visitor==0.1.3
      - werkzeug==2.0.3
      - wtforms==3.0.0
prefix: /opt/conda/envs/porthole

tests/test_Queries.py::TestRowDict::test_unique_field_name_constraint
tests/test_Queries.py::TestQueries::test_QueryExecutor tests/test_Queries.py::TestQueries::test_queryreader_missing_param tests/test_Queries.py::TestQueries::test_queryreader_no_params tests/test_Queries.py::TestQueries::test_queryreader_params tests/test_Queries.py::TestQueries::test_queryreader_validate
tests/test_Queries.py::TestQueries::test_queryresult tests/test_Queries.py::TestQueries::test_queryresult_map tests/test_Queries.py::TestRowDict::test_behavior tests/test_Queries.py::TestRowDict::test_init tests/test_Queries.py::TestRowDict::test_iteration
porthole/queries.py
porthole/queries.py