diff --git a/tableaudocumentapi/datasource.py b/tableaudocumentapi/datasource.py
index 93ebe55..617004a 100644
--- a/tableaudocumentapi/datasource.py
+++ b/tableaudocumentapi/datasource.py
@@ -72,7 +72,7 @@ class Datasource(object):
         """
 
         # save the file
-        self._datasourceTree.write(self._filename)
+        self._datasourceTree.write(self._filename, encoding="utf-8", xml_declaration=True)
 
     def save_as(self, new_filename):
         """
@@ -85,7 +85,7 @@ class Datasource(object):
             Nothing.
 
         """
-        self._datasourceTree.write(new_filename)
+        self._datasourceTree.write(new_filename, encoding="utf-8", xml_declaration=True)
 
     ###########
     # name
diff --git a/tableaudocumentapi/workbook.py b/tableaudocumentapi/workbook.py
index 67dbc32..889f746 100644
--- a/tableaudocumentapi/workbook.py
+++ b/tableaudocumentapi/workbook.py
@@ -76,7 +76,7 @@ class Workbook(object):
         """
 
         # save the file
-        self._workbookTree.write(self._filename)
+        self._workbookTree.write(self._filename, encoding="utf-8", xml_declaration=True)
 
     def save_as(self, new_filename):
         """
@@ -90,7 +90,7 @@ class Workbook(object):
 
         """
 
-        self._workbookTree.write(new_filename)
+        self._workbookTree.write(new_filename, encoding="utf-8", xml_declaration=True)
 
     ###########################################################################
     #

Tabcmd publish with .twb created via Document API
I can successfully create a .twb file via the Document API, but attempting to publish it to my Tableau Server via Tabcmd results in an unexpected error:

**Bad request
unexpected error occurred opening the packaged workbook.**

Attached is the template workbook created in Tableau Desktop (superstore_sales.twb) and one of the workbooks created from that template via the Document API (superstore_sales_arizona.twb)

[superstore_twbs.zip](https://github.com/tableau/document-api-python/files/285303/superstore_twbs.zip)


diff --git a/test.py b/test.py
index fd7d1bd..5606005 100644
--- a/test.py
+++ b/test.py
@@ -17,6 +17,7 @@ TABLEAU_10_WORKBOOK = '''<?xml version='1.0' encoding='utf-8' ?><workbook source
 TABLEAU_CONNECTION_XML = ET.fromstring(
     '''<connection authentication='sspi' class='sqlserver' dbname='TestV1' odbc-native-protocol='yes' one-time-sql='' server='mssql2012.test.tsi.lan' username=''></connection>''')
 
+
 class HelperMethodTests(unittest.TestCase):
 
     def test_is_valid_file_with_valid_inputs(self):
@@ -39,7 +40,6 @@ class ConnectionParserTests(unittest.TestCase):
         self.assertIsInstance(connections[0], Connection)
         self.assertEqual(connections[0].dbname, 'TestV1')
 
-
     def test_can_extract_federated_connections(self):
         parser = ConnectionParser(ET.fromstring(TABLEAU_10_TDS), '10.0')
         connections = parser.get_connections()
@@ -97,6 +97,17 @@ class DatasourceModelTests(unittest.TestCase):
         new_tds = Datasource.from_file(self.tds_file.name)
         self.assertEqual(new_tds.connections[0].dbname, 'newdb.test.tsi.lan')
 
+    def test_save_has_xml_declaration(self):
+        original_tds = Datasource.from_file(self.tds_file.name)
+        original_tds.connections[0].dbname = 'newdb.test.tsi.lan'
+
+        original_tds.save()
+
+        with open(self.tds_file.name) as f:
+            first_line = f.readline().strip()  # first line should be xml tag
+            self.assertEqual(
+                first_line, "<?xml version='1.0' encoding='utf-8'?>")
+
 
 class WorkbookModelTests(unittest.TestCase):
 
@@ -122,7 +133,8 @@ class WorkbookModelTests(unittest.TestCase):
         original_wb.save()
 
         new_wb = Workbook(self.workbook_file.name)
-        self.assertEqual(new_wb.datasources[0].connections[0].dbname, 'newdb.test.tsi.lan')
+        self.assertEqual(new_wb.datasources[0].connections[
+                         0].dbname, 'newdb.test.tsi.lan')
 
 
 class WorkbookModelV10Tests(unittest.TestCase):
@@ -152,7 +164,19 @@ class WorkbookModelV10Tests(unittest.TestCase):
         original_wb.save()
 
         new_wb = Workbook(self.workbook_file.name)
-        self.assertEqual(new_wb.datasources[0].connections[0].dbname, 'newdb.test.tsi.lan')
+        self.assertEqual(new_wb.datasources[0].connections[
+                         0].dbname, 'newdb.test.tsi.lan')
+
+    def test_save_has_xml_declaration(self):
+        original_wb = Workbook(self.workbook_file.name)
+        original_wb.datasources[0].connections[0].dbname = 'newdb.test.tsi.lan'
+
+        original_wb.save()
+
+        with open(self.workbook_file.name) as f:
+            first_line = f.readline().strip()  # first line should be xml tag
+            self.assertEqual(
+                first_line, "<?xml version='1.0' encoding='utf-8'?>")
 
 if __name__ == '__main__':
     unittest.main()

pip install -e .
parse_log_pytest
pytest
pytest
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
packaging @ file:///croot/packaging_1734472117206/work
pluggy @ file:///croot/pluggy_1733169602837/work
pytest @ file:///croot/pytest_1738938843180/work
-e git+https://github.com/tableau/document-api-python.git@07aad9550d3d36a4d74c4751832c50fe81882a01#egg=tableaudocumentapi
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work

name: document-api-python
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
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_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
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=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
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
prefix: /opt/conda/envs/document-api-python

test.py::DatasourceModelTests::test_save_has_xml_declaration test.py::WorkbookModelV10Tests::test_save_has_xml_declaration
test.py::HelperMethodTests::test_is_valid_file_with_invalid_inputs test.py::HelperMethodTests::test_is_valid_file_with_valid_inputs test.py::ConnectionParserTests::test_can_extract_federated_connections test.py::ConnectionParserTests::test_can_extract_legacy_connection test.py::ConnectionModelTests::test_can_read_attributes_from_connection test.py::ConnectionModelTests::test_can_write_attributes_to_connection test.py::DatasourceModelTests::test_can_extract_connection test.py::DatasourceModelTests::test_can_extract_datasource_from_file test.py::DatasourceModelTests::test_can_save_tds test.py::WorkbookModelTests::test_can_extract_datasource test.py::WorkbookModelTests::test_can_update_datasource_connection_and_save test.py::WorkbookModelV10Tests::test_can_extract_datasourceV10 test.py::WorkbookModelV10Tests::test_can_update_datasource_connection_and_saveV10
tableaudocumentapi/datasource.py tableaudocumentapi/workbook.py
tableaudocumentapi/datasource.py tableaudocumentapi/workbook.py