From 7d79b02d66fd2fd2259ad49ef4cd0e1f0811ae12 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Tue, 16 Jun 2026 23:22:56 -0700 Subject: [PATCH 1/3] fix: improve timeout error messages and document TSC_CHUNK_SIZE_MB When a 504 occurs during an async chunked upload, the error message now hints at reducing TSC_CHUNK_SIZE_MB rather than suggesting async mode (which the user is already using). Also document the env var in the publish docstrings for workbooks and datasources. Co-Authored-By: Claude Sonnet 4.6 --- .../server/endpoint/datasources_endpoint.py | 14 +++++++++++--- .../server/endpoint/workbooks_endpoint.py | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/tableauserverclient/server/endpoint/datasources_endpoint.py b/tableauserverclient/server/endpoint/datasources_endpoint.py index a346c2730..a43b45ea1 100644 --- a/tableauserverclient/server/endpoint/datasources_endpoint.py +++ b/tableauserverclient/server/endpoint/datasources_endpoint.py @@ -580,7 +580,9 @@ def publish( as_job : bool, default False If True, the publish operation is asynchronous and returns a job item. If False, the publish operation is synchronous and returns a - datasource item. + datasource item. For large files on slow connections, if uploads + time out you can tune the chunk size with the TSC_CHUNK_SIZE_MB + environment variable (default: 50). Returns ------- @@ -670,8 +672,14 @@ def publish( try: server_response = self.post_request(url, xml_request, content_type) except InternalServerError as err: - if err.code == 504 and not as_job: - err.content = "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts." + if err.code == 504: + if as_job: + err.content = ( + "Timeout error during chunked file upload. Try reducing the chunk size by setting the " + "TSC_CHUNK_SIZE_MB environment variable to a lower value (current default: 50)." + ) + else: + err.content = "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts." raise err if as_job: diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index 14297518a..65416c1d5 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -854,7 +854,9 @@ def publish( as_job : bool, default False Set to True to run the upload as a job (asynchronous upload). If set to True a job will start to perform the publishing process and a Job - object is returned. Defaults to False. + object is returned. Defaults to False. For large files on slow + connections, if uploads time out you can tune the chunk size with + the TSC_CHUNK_SIZE_MB environment variable (default: 50). skip_connection_check : bool, default False Set to True to skip connection check at time of upload. Publishing @@ -976,8 +978,14 @@ def publish( try: server_response = self.post_request(url, xml_request, content_type, parameters) except InternalServerError as err: - if err.code == 504 and not as_job: - err.content = "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts." + if err.code == 504: + if as_job: + err.content = ( + "Timeout error during chunked file upload. Try reducing the chunk size by setting the " + "TSC_CHUNK_SIZE_MB environment variable to a lower value (current default: 50)." + ) + else: + err.content = "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts." raise err if as_job: From 3d0082de756c7dd7f5248f84b91c06bf0ff3ada6 Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Tue, 16 Jun 2026 23:32:16 -0700 Subject: [PATCH 2/3] style: apply black formatting Co-Authored-By: Claude Sonnet 4.6 --- tableauserverclient/server/endpoint/datasources_endpoint.py | 4 +++- tableauserverclient/server/endpoint/workbooks_endpoint.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tableauserverclient/server/endpoint/datasources_endpoint.py b/tableauserverclient/server/endpoint/datasources_endpoint.py index a43b45ea1..ec52d3004 100644 --- a/tableauserverclient/server/endpoint/datasources_endpoint.py +++ b/tableauserverclient/server/endpoint/datasources_endpoint.py @@ -679,7 +679,9 @@ def publish( "TSC_CHUNK_SIZE_MB environment variable to a lower value (current default: 50)." ) else: - err.content = "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts." + err.content = ( + "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts." + ) raise err if as_job: diff --git a/tableauserverclient/server/endpoint/workbooks_endpoint.py b/tableauserverclient/server/endpoint/workbooks_endpoint.py index 65416c1d5..7ebdcab56 100644 --- a/tableauserverclient/server/endpoint/workbooks_endpoint.py +++ b/tableauserverclient/server/endpoint/workbooks_endpoint.py @@ -985,7 +985,9 @@ def publish( "TSC_CHUNK_SIZE_MB environment variable to a lower value (current default: 50)." ) else: - err.content = "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts." + err.content = ( + "Timeout error while publishing. Please use asynchronous publishing to avoid timeouts." + ) raise err if as_job: From e165e7d01214b5e219d6da3d6b4f42e060deb85c Mon Sep 17 00:00:00 2001 From: Jac Fitzgerald Date: Tue, 16 Jun 2026 23:38:59 -0700 Subject: [PATCH 3/3] test: add tests for async publish 504 timeout error message Co-Authored-By: Claude Sonnet 4.6 --- test/test_datasource.py | 16 ++++++++++++++++ test/test_workbook.py | 11 +++++++++++ 2 files changed, 27 insertions(+) diff --git a/test/test_datasource.py b/test/test_datasource.py index a0890f3a5..d3dd0fe79 100644 --- a/test/test_datasource.py +++ b/test/test_datasource.py @@ -763,6 +763,22 @@ def test_synchronous_publish_timeout_error(server) -> None: ) +def test_async_publish_timeout_error(server) -> None: + with requests_mock.mock() as m: + m.register_uri("POST", server.datasources.baseurl, status_code=504) + + new_datasource = TSC.DatasourceItem(project_id="") + publish_mode = server.PublishMode.CreateNew + + with pytest.raises(InternalServerError, match="TSC_CHUNK_SIZE_MB"): + server.datasources.publish( + new_datasource, + TEST_ASSET_DIR / "SampleDS.tds", + publish_mode, + as_job=True, + ) + + def test_delete_extracts(server) -> None: server.version = "3.10" with requests_mock.mock() as m: diff --git a/test/test_workbook.py b/test/test_workbook.py index c5c4f6662..1232650d9 100644 --- a/test/test_workbook.py +++ b/test/test_workbook.py @@ -879,6 +879,17 @@ def test_synchronous_publish_timeout_error(server: TSC.Server) -> None: server.workbooks.publish(new_workbook, TEST_ASSET_DIR / "SampleWB.twbx", publish_mode) +def test_async_publish_timeout_error(server: TSC.Server) -> None: + with requests_mock.mock() as m: + m.register_uri("POST", server.workbooks.baseurl, status_code=504) + + new_workbook = TSC.WorkbookItem(project_id="") + publish_mode = server.PublishMode.CreateNew + + with pytest.raises(InternalServerError, match="TSC_CHUNK_SIZE_MB"): + server.workbooks.publish(new_workbook, TEST_ASSET_DIR / "SampleWB.twbx", publish_mode, as_job=True) + + def test_delete_extracts_all(server: TSC.Server) -> None: server.version = "3.10" server.workbooks.baseurl