diff --git a/docs/source/translation/zone_window.rst b/docs/source/translation/zone_window.rst
index 480fe5db..5062926c 100644
--- a/docs/source/translation/zone_window.rst
+++ b/docs/source/translation/zone_window.rst
@@ -13,17 +13,21 @@ assumed to mean the sum of the areas of the windows that the ``Window`` element
 represents. Each ``Window`` is then assigned to a side of the building in one of
 two ways:
 
-   #. By association with a particular wall.
    #. By inspecting the azimuth or orientation of the window.
+   #. By association with a particular wall.
    
-If an HPXML window has the ``AttachedToWall`` element, the id reference in that
-element is used to find the associated wall and the side of the building that
-the window faces is inferred from the :ref:`wall orientation <wallorientation>`.
-
-If there is not an ``AttachedToWall`` element, the side is determined via the
-``Azimuth`` or ``Orientation`` elements with preference given to the
-``Azimuth`` if present. If the window falls between two sides of the house, the
-window area is divided between the sides of the house evenly. 
+If there is an ``Orientation`` or ``Azimuth`` element, the side is determined
+via the one of those elements with preference given to the ``Azimuth`` if
+present. If the window falls between two sides of the house, the window area is
+divided between the sides of the house evenly. 
+
+If ``Orientation`` or ``Azimuth`` are missing and the HPXML window has the
+``AttachedToWall`` element, the id reference in that element is used to find the
+associated wall and the side of the building that the window faces is inferred
+from the :ref:`wall orientation <wallorientation>`. If the window is attached to
+a foundation wall, the orientation/azimuth must be provided on the ``Window``
+element because foundation walls do not have orientation or azimuth elements
+available.
 
 The areas on each side of the house are summed and the :ref:`window-prop` are
 determined independently for each side of the house. Since HPXML requires that
diff --git a/hescorehpxml/__init__.py b/hescorehpxml/__init__.py
index 55a58b86..102d0f48 100644
--- a/hescorehpxml/__init__.py
+++ b/hescorehpxml/__init__.py
@@ -1530,29 +1530,33 @@ class HPXMLtoHEScoreTranslator(object):
 
             # Window side
             window_sides = []
-            attached_to_wall_id = xpath(hpxmlwndw, 'h:AttachedToWall/@idref')
-            if attached_to_wall_id is not None:
-                # Give preference to the Attached to Wall element to determine the side of the house.
-                for side, walls in list(hpxmlwalls.items()):
-                    for wall in walls:
-                        if attached_to_wall_id == wall['id']:
-                            window_sides.append(side)
-                            break
+            window_id = xpath(hpxmlwndw, 'h:SystemIdentifier/@id')
+            try:
+                # Get the aziumuth or orientation if they exist
+                wndw_azimuth = self.get_nearest_azimuth(xpath(hpxmlwndw, 'h:Azimuth/text()'),
+                                                        xpath(hpxmlwndw, 'h:Orientation/text()'))
+            except TranslationError:
+                # The window doesn't have orientation/azimuth information, get from wall
+                attached_to_wall_id = xpath(hpxmlwndw, 'h:AttachedToWall/@idref')
+                if attached_to_wall_id is not None:
+                    for side, walls in list(hpxmlwalls.items()):
+                        for wall in walls:
+                            if attached_to_wall_id == wall['id']:
+                                window_sides.append(side)
+                                break
+                    if not window_sides:
+                        raise TranslationError('The Window[SystemIdentifier/@id="{}"] has no Azimuth or Orientation, and the Window/AttachedToWall/@idref of "{}" didn\'t reference a Wall element.'.format(window_id, attached_to_wall_id))  # noqa: E501
+                else:
+                    raise TranslationError(
+                        'Window[SystemIdentifier/@id="{}"] doesn\'t have Azimuth, Orientation, or AttachedToWall. At least one is required.'.format(window_id)  # noqa: E501
+                    )
             else:
-                # If there's not Attached to Wall element, figure it out from the Azimuth/Orientation
+                # Azimuth found, associate with a side
                 try:
-                    wndw_azimuth = self.get_nearest_azimuth(xpath(hpxmlwndw, 'h:Azimuth/text()'),
-                                                            xpath(hpxmlwndw, 'h:Orientation/text()'))
-                except TranslationError:
-                    # there's no directional information in the window
-                    raise TranslationError(
-                        'All windows need to have either an AttachedToWall, Orientation, or Azimuth sub element.')
-                else:
-                    try:
-                        window_sides = [sidemap[wndw_azimuth]]
-                    except KeyError:
-                        # the direction of the window is between sides, split area
-                        window_sides = [sidemap[unspin_azimuth(wndw_azimuth + x)] for x in (-45, 45)]
+                    window_sides = [sidemap[wndw_azimuth]]
+                except KeyError:
+                    # the direction of the window is between sides, split area
+                    window_sides = [sidemap[unspin_azimuth(wndw_azimuth + x)] for x in (-45, 45)]
 
             # Assign properties and areas to the correct side of the house
             windowd['area'] /= float(len(window_sides))

Better handle windows attached to foundation walls
If a window is attached to a foundation wall it will try to determine the orientation from the wall but won't be able to find it (It's not looking for foundation walls and they don't have orientation anyway). We should fall back to using the orientation from the window itself in that case. 
diff --git a/tests/tests.py b/tests/tests.py
index 1f6fd6cb..31a901bc 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -333,9 +333,23 @@ class TestOtherHouses(unittest.TestCase, ComparatorBase):
         el.getparent().remove(el)
         self.assertRaisesRegexp(
             TranslationError,
-            r'All windows need to have either an AttachedToWall, Orientation, or Azimuth sub element\.',
+            r'Window\[SystemIdentifier/@id="\w+"\] doesn\'t have Azimuth, Orientation, or AttachedToWall. At least one is required.',  # noqa E501
             tr.hpxml_to_hescore_dict)
 
+    def test_window_only_attached_to_foundation_wall(self):
+        tr = self._load_xmlfile('house4')
+        window_orientation = self.xpath('//h:Window[1]/h:Orientation')
+        window = window_orientation.getparent()
+        etree.SubElement(window, tr.addns('h:AttachedToWall'), attrib={'idref': 'crawlwall'})
+        self._do_compare('house4')
+
+        window.remove(window_orientation)
+        self.assertRaisesRegexp(
+            TranslationError,
+            r'The Window\[SystemIdentifier/@id="\w+"\] has no Azimuth or Orientation, and the .* didn\'t reference a Wall element.',  # noqa E501
+            tr.hpxml_to_hescore_dict
+        )
+
     def test_window_attached_to_wall(self):
         filebase = 'house6'
         tr = self._load_xmlfile(filebase)

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
anyio==4.9.0
babel==2.17.0
certifi==2025.1.31
charset-normalizer==3.4.1
click==8.1.8
colorama==0.4.6
coverage==7.8.0
docutils==0.21.2
exceptiongroup==1.2.2
flake8==7.2.0
future==1.0.0
h11==0.14.0
-e git+https://github.com/NREL/hescore-hpxml.git@0b79d17c5fff0876a18ccd2efca3d058323d7810#egg=hescore_hpxml
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
Jinja2==3.1.6
lxml==5.3.1
MarkupSafe==3.0.2
mccabe==0.7.0
packaging==24.2
pluggy==1.5.0
pycodestyle==2.13.0
pyflakes==3.3.2
Pygments==2.19.1
pytest==8.3.5
requests==2.32.3
sniffio==1.3.1
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-autobuild==2024.10.3
sphinx-rtd-theme==3.0.2
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
starlette==0.46.1
tomli==2.2.1
typing_extensions==4.13.0
urllib3==2.3.0
uvicorn==0.34.0
watchfiles==1.0.4
websockets==15.0.1
zipp==3.21.0

name: hescore-hpxml
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
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - anyio==4.9.0
      - babel==2.17.0
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - click==8.1.8
      - colorama==0.4.6
      - coverage==7.8.0
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - flake8==7.2.0
      - future==1.0.0
      - h11==0.14.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - lxml==5.3.1
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - packaging==24.2
      - pluggy==1.5.0
      - pycodestyle==2.13.0
      - pyflakes==3.3.2
      - pygments==2.19.1
      - pytest==8.3.5
      - requests==2.32.3
      - sniffio==1.3.1
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-autobuild==2024.10.3
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - starlette==0.46.1
      - tomli==2.2.1
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - uvicorn==0.34.0
      - watchfiles==1.0.4
      - websockets==15.0.1
      - zipp==3.21.0
prefix: /opt/conda/envs/hescore-hpxml

tests/tests.py::TestOtherHouses::test_missing_window_orientation tests/tests.py::TestOtherHouses::test_window_only_attached_to_foundation_wall
tests/tests.py::TestAPIHouses::test_house1 tests/tests.py::TestAPIHouses::test_house1_v1_1 tests/tests.py::TestAPIHouses::test_house1_v2 tests/tests.py::TestAPIHouses::test_house1_v2_1 tests/tests.py::TestAPIHouses::test_house2 tests/tests.py::TestAPIHouses::test_house3 tests/tests.py::TestAPIHouses::test_house4 tests/tests.py::TestAPIHouses::test_house5 tests/tests.py::TestAPIHouses::test_house6 tests/tests.py::TestAPIHouses::test_house7 tests/tests.py::TestAPIHouses::test_house8 tests/tests.py::TestOtherHouses::test_air_source_heat_pump_has_no_ducts tests/tests.py::TestOtherHouses::test_attic_knee_wall tests/tests.py::TestOtherHouses::test_attic_knee_wall_zero_rvalue tests/tests.py::TestOtherHouses::test_attic_roof_assoc tests/tests.py::TestOtherHouses::test_bad_duct_location tests/tests.py::TestOtherHouses::test_bldgid_not_found tests/tests.py::TestOtherHouses::test_clg_sys_has_air_dist tests/tests.py::TestOtherHouses::test_cooling_system_wrong_efficiency_type tests/tests.py::TestOtherHouses::test_dist_sys_idref tests/tests.py::TestOtherHouses::test_evap_cooling_system_type tests/tests.py::TestOtherHouses::test_external_id_extension_passthru tests/tests.py::TestOtherHouses::test_external_id_passthru tests/tests.py::TestOtherHouses::test_extra_roof_sheathing_insulation tests/tests.py::TestOtherHouses::test_extra_wall_sheathing_insulation tests/tests.py::TestOtherHouses::test_floor_no_area tests/tests.py::TestOtherHouses::test_foundation_walls_on_slab tests/tests.py::TestOtherHouses::test_heating_system_no_efficiency tests/tests.py::TestOtherHouses::test_heating_system_wrong_efficiency_type tests/tests.py::TestOtherHouses::test_heatpump_no_cooling tests/tests.py::TestOtherHouses::test_heatpump_no_heating tests/tests.py::TestOtherHouses::test_hescore_min tests/tests.py::TestOtherHouses::test_htg_sys_has_air_dist tests/tests.py::TestOtherHouses::test_hvac_fractions_sum_to_one tests/tests.py::TestOtherHouses::test_impossible_cooling_system_type tests/tests.py::TestOtherHouses::test_impossible_heating_system_type tests/tests.py::TestOtherHouses::test_impossible_triple_pane_window tests/tests.py::TestOtherHouses::test_impossible_window tests/tests.py::TestOtherHouses::test_indirect_dhw_error tests/tests.py::TestOtherHouses::test_invalid_attic_type tests/tests.py::TestOtherHouses::test_invalid_residential_faciliy_type tests/tests.py::TestOtherHouses::test_invalid_roof_type tests/tests.py::TestOtherHouses::test_invalid_surroundings tests/tests.py::TestOtherHouses::test_log_wall_fail tests/tests.py::TestOtherHouses::test_mentor_extension tests/tests.py::TestOtherHouses::test_missing_attached_to_roof tests/tests.py::TestOtherHouses::test_missing_cooling_system tests/tests.py::TestOtherHouses::test_missing_cooling_weighting_factor tests/tests.py::TestOtherHouses::test_missing_heating_system tests/tests.py::TestOtherHouses::test_missing_heating_weighting_factor tests/tests.py::TestOtherHouses::test_missing_residential_facility_type tests/tests.py::TestOtherHouses::test_missing_roof_color tests/tests.py::TestOtherHouses::test_missing_roof_type tests/tests.py::TestOtherHouses::test_missing_siding tests/tests.py::TestOtherHouses::test_missing_skylight_area tests/tests.py::TestOtherHouses::test_missing_surroundings tests/tests.py::TestOtherHouses::test_missing_water_heater tests/tests.py::TestOtherHouses::test_missing_window_area tests/tests.py::TestOtherHouses::test_only_duct_system_per_heating_sys tests/tests.py::TestOtherHouses::test_ove_low_r tests/tests.py::TestOtherHouses::test_preconstruction_event_type tests/tests.py::TestOtherHouses::test_siding_cmu_fail tests/tests.py::TestOtherHouses::test_siding_fail2 tests/tests.py::TestOtherHouses::test_tankless_coil_dhw_error tests/tests.py::TestOtherHouses::test_too_many_duct_systems tests/tests.py::TestOtherHouses::test_townhouse_walls tests/tests.py::TestOtherHouses::test_townhouse_walls_all_same tests/tests.py::TestOtherHouses::test_townhouse_walls_conflict tests/tests.py::TestOtherHouses::test_townhouse_window_fail tests/tests.py::TestOtherHouses::test_townhouse_window_wall_all_same_fail tests/tests.py::TestOtherHouses::test_townhouse_windows_area_wrong tests/tests.py::TestOtherHouses::test_wall_construction_ps_low_r tests/tests.py::TestOtherHouses::test_wall_insulation_layer_missing_rvalue tests/tests.py::TestOtherHouses::test_wall_same_area_same_side_different_construction tests/tests.py::TestOtherHouses::test_window_area_sum_on_angled_front_door tests/tests.py::TestOtherHouses::test_window_attached_to_wall tests/tests.py::TestOtherHouses::test_wood_stove tests/tests.py::TestOtherHouses::test_wood_stove_invalid_fuel_type tests/tests.py::TestOtherHouses::test_zipcode_missing tests/tests.py::TestInputOutOfBounds::test_assessment_date1 tests/tests.py::TestInputOutOfBounds::test_assessment_date2 tests/tests.py::TestInputOutOfBounds::test_conditioned_floor_area1 tests/tests.py::TestInputOutOfBounds::test_conditioned_floor_area2 tests/tests.py::TestInputOutOfBounds::test_cooling_efficiency tests/tests.py::TestInputOutOfBounds::test_cooling_year tests/tests.py::TestInputOutOfBounds::test_dhw_heat_pump_efficiency tests/tests.py::TestInputOutOfBounds::test_dhw_storage_efficiency tests/tests.py::TestInputOutOfBounds::test_dhw_year tests/tests.py::TestInputOutOfBounds::test_envelope_leakage tests/tests.py::TestInputOutOfBounds::test_evap_cooler_missing_efficiency tests/tests.py::TestInputOutOfBounds::test_floor_to_ceiling_height1 tests/tests.py::TestInputOutOfBounds::test_floor_to_ceiling_height2 tests/tests.py::TestInputOutOfBounds::test_heating_efficiency_furnace tests/tests.py::TestInputOutOfBounds::test_heating_efficiency_gchp tests/tests.py::TestInputOutOfBounds::test_heating_efficiency_heat_pump tests/tests.py::TestInputOutOfBounds::test_heating_year tests/tests.py::TestInputOutOfBounds::test_num_floor_above_grade tests/tests.py::TestInputOutOfBounds::test_skylight_area tests/tests.py::TestInputOutOfBounds::test_skylight_u_value tests/tests.py::TestInputOutOfBounds::test_window_area tests/tests.py::TestInputOutOfBounds::test_window_u_value tests/tests.py::TestInputOutOfBounds::test_year_built1 tests/tests.py::TestInputOutOfBounds::test_year_built2 tests/tests.py::TestHVACFractions::test_allow_5pct_diff tests/tests.py::TestHVACFractions::test_boiler_roomac tests/tests.py::TestHVACFractions::test_furnace_baseboard_centralac tests/tests.py::TestHVACFractions::test_furnace_heat_pump tests/tests.py::TestHVACFractions::test_wall_furnace_baseboard_centralac tests/tests.py::TestPhotovoltaics::test_azimuth_orientation_missing tests/tests.py::TestPhotovoltaics::test_capacity_missing tests/tests.py::TestPhotovoltaics::test_collector_area tests/tests.py::TestPhotovoltaics::test_orientation tests/tests.py::TestPhotovoltaics::test_pv tests/tests.py::TestPhotovoltaics::test_two_sys_avg tests/tests.py::TestPhotovoltaics::test_two_sys_different_capacity_error tests/tests.py::TestPhotovoltaics::test_years_missing tests/tests.py::TesHPXMLVersion2Point3::test_floor_furnace tests/tests.py::TesHPXMLVersion2Point3::test_medium_dark_roof_color tests/tests.py::TesHPXMLVersion2Point3::test_roof_absorptance tests/tests.py::TestHEScore2019Updates::test_bldg_about_comment tests/tests.py::TestHEScore2019Updates::test_conditioned_attic tests/tests.py::TestHEScore2019Updates::test_duct_location_validation tests/tests.py::TestHEScore2019Updates::test_hpwes tests/tests.py::TestHEScore2019Updates::test_hpwes_fail tests/tests.py::TestHEScore2019Updates::test_hvac_combinations tests/tests.py::TestHEScore2019Updates::test_mini_split_cooling_only tests/tests.py::TestHEScore2019Updates::test_skylight_solar_screens_exteriorshading tests/tests.py::TestHEScore2019Updates::test_skylight_solar_screens_treatments tests/tests.py::TestHEScore2019Updates::test_tankless tests/tests.py::TestHEScore2019Updates::test_tankless_energyfactorerror tests/tests.py::TestHEScore2019Updates::test_uef_over_ef tests/tests.py::TestHEScore2019Updates::test_uef_with_tankless tests/tests.py::TestHEScore2019Updates::test_window_code_mappings_aluminum tests/tests.py::TestHEScore2019Updates::test_window_solar_screens
docs/source/translation/zone_window.rst hescorehpxml/__init__.py
docs/source/translation/zone_window.rst hescorehpxml/__init__.py