Skip to content

server_address doesn't get updated on workbook publish #337

Open

Description

@justyns

I'm working on a script that would push one workbook to multiple Tableau sites. Each site has a different database to connect to, so the embedded connection needs to be updated appropriately.

I'm trying to accomplish this by updating the embedded datasource connection information in the packaged workbook. Feel free to let me know if there's a better way to do this as I'm new to Tableau in general.

Currently, I have this:

    conn_creds = TSC.ConnectionCredentials(name=rds_user,
                                           password=rds_pass)

    # Create a connection and add the above credentials to it
    connection = TSC.ConnectionItem()
    connection.server_address = rds_host
    connection.server_port = rds_port
    connection.connection_credentials = conn_creds

    # Publish the workbook to tableau
    publish_item = server.workbooks.publish(new_workbook,
                                            workbook_file,
                                            publish_mode,
                                            connections=[connection])

This seems to work if the workbook was exported with the server_address set to the same thing as my rds_host above. So if rds_host and the server address in the workbook are both dev.example.com, it will update the credentials and publish correctly.

However, if rds_host is production.example.com and the workbook has dev.example.com, Tableau returns a failed to establish a connection to your datasource error message even though the credentials are correct.

Before I tried the above solution, I was using the (now deprecated?) connection_credentials attribute like this:

    conn_creds = TSC.ConnectionCredentials(name=rds_user,
                                           password=rds_pass)

    # Publish the workbook to tableau
    publish_item = server.workbooks.publish(new_workbook,
                                            workbook_file,
                                            publish_mode,
                                            connection_credentials=conn_creds)

This had the same effect of updating the username/password correctly, but would not update the server_address.

https://tableau.github.io/server-client-python/docs/api-ref#workbooks under workbooks.publish actually does not mention the connections= attribute at all, only connection_credentials. There was a warning message logged saying it was deprecated that lead me to use connections.

https://tableau.github.io/server-client-python/docs/api-ref#connections under ConnectionCredentials class mentions server_address and server_port attributes, but they don't seem to exist in https://github.com/tableau/server-client-python/blob/v0.7/tableauserverclient/models/connection_credentials.py and aren't used in https://github.com/tableau/server-client-python/blob/v0.7/tableauserverclient/server/request_factory.py#L38

Please let me know if I need to clarify anything or if more information is needed. I haven't looked at the code too much for this library yet, but when I get some time I planned on testing the same process with the rest api directly to verify that it isn't an issue with the server api itself.

Activity

  1. ausiddiqui commented on Oct 9, 2018

    @ausiddiqui

    The server_address and server_port are part of ConnectionItem().

    In any case, what error do you get? I've never been able to get the list of TSC.ConnectionItem() objects embedded to to work. The error I have gotten is

    ServerResponseError: 
    
    	400000: Bad Request
    		Payload is either malformed XML/JSON or incomplete

    This is at the Committing file upload stage, after chunking the file already. I am using the Development branch so as to have this commit incorporated.

  2. zeniazenin commented on Nov 5, 2018

    @zeniazenin

    I am trying to do the same thing and getting same result -
    I need to publish same workbook to multiple sites and update connection server and port for each. When I try to do it it gives me "1 failed to establish a connection to your datasource." error.

    CODE:
    connection1 = ConnectionItem()
    connection1.server_address = "192.168.1.201"
    connection1.server_port = "3306"
    connection1.connection_credentials = ConnectionCredentials("tableau", "samplepassword", True)

  3. AlexandreRodrigues1 commented on Jun 5, 2019

    @AlexandreRodrigues1

    The same problem but it appears to be, at least in my case, a Tableau Server issue. When I try to upload a workbook using the following code:

    Tableau_auth = TSC.TableauAuth('TableauUser', 'TableauPass', site_id='SITENAME')
    server = TSC.Server('https://TABLEUA_SERVER UTL ',use_server_version=True) 
    with server.auth.sign_in(tableau_auth):
        wb_item = TSC.WorkbookItem(name='test_workbook', project_id='project.id', show_tabs=True)
        conn = TSC.ConnectionItem()
        conn.server_address = "SQLServerIP,Port"
        conn.connection_credentials = TSC.ConnectionCredentials("user", "pass", True)
        CreateNew = TSC.Server.PublishMode.CreateNew
        wb_item = server.workbooks.publish(wb_item, 'test_workbook'.twb', CreateNew,                                      connections=[conn])
    

    It only uploads the workbook if the conn.server_address is correct (or not defined) and if the datasource server, defined in the workbook, is correct also. If one of the IP addresses, mentioned before, is incorrect it will not upload the workbook giving the following message:

    403007: Forbidden
    test_workbook failed to establish a connection to your datasource.

    The xml generated by TSC library appears to be fine:

    <?xml version="1.0" encoding="UTF-8"?>
    <tsRequest>
       <workbook name="...." showTabs="true">
          <project id="......" />
          <connections>
             <connection serverAddress="IP,PORT">
                <connectionCredentials embed="true" name="...." password="....." />
             </connection>
          </connections>
       </workbook>
    </tsRequest>
    

    Tableau Server Version: 2018.3.2 (20183.18.1214.0808) 64-bit Windows
    TCS 0.8
    SQL SERVER 2017

  4. p051tr0n commented on Jun 25, 2019

    @p051tr0n

    This is still very much an issue. The documentation seems to be incorrect as OP pointed out, and for whatever reason the python client still gives off that 403007 error when attempting to publish a workbook that has any live connections/datasources attached to it.
    Also, there is 0 documentation on the error code 403007.
    Ive been working on it for 2 months now with no progress. Hopefully I can find an answer soon and will submit it here since there seems to be little to no attention from Tableau on this.

    UPDATE ----

    Looking into this more, I found that the REST API call to publish a workbook has all of the parameters you need for adding a new workbook with datasources that require credentials:

     <connection serverAddress="server-address" serverPort="port-number">
        <connectionCredentials name="connection-username" password="connection-password"
              embed="embed-flag" oAuth="oauth-flag" />
        </connection>
        </connections>
    

    https://onlinehelp.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#publish_workbook

    But when you look inside of the request factory module, you find the following:

    def _add_connections_element(connections_element, connection):
        connection_element = ET.SubElement(connections_element, 'connection')
        connection_element.attrib['serverAddress'] = connection.server_address
        if connection.server_port:
            connection_element.attrib['serverPort'] = connection.server_port
        if connection.connection_credentials:
            connection_credentials = connection.connection_credentials
            _add_credentials_element(connection_element, connection_credentials)
    
    
    def _add_credentials_element(parent_element, connection_credentials):
        credentials_element = ET.SubElement(parent_element, 'connectionCredentials')
        credentials_element.attrib['name'] = connection_credentials.name
        credentials_element.attrib['password'] = connection_credentials.password
        credentials_element.attrib['embed'] = 'true' if connection_credentials.embed else 'false'
        if connection_credentials.oauth:
            credentials_element.attrib['oAuth'] = 'true'
    

    and you will receive the error stating "You cannot add both" should you try to, even though clearly both are needed should you want to do this via the tableauclientserver module.

    Once I write the code in python to do the API call (which will be using JSON, not the overly complicated XML) I will post here if I can confirm it working.

    ---- UPDATE

    It currently looks like by adding in the connection info into the request payload as shown in the documentation, the server returns that it is malformed. Im hoping to find out the proper way to add it in there, after which this issue might actually get resolved for some of us.

    ---- UPDATE

    I was able to successfully combine the connection and credentials fields but I had to use XML as there is no documentation on what form the JSON must be in to be accepted, and following the usual conversion from the doc caused a malformed error.

    At this point the only thing it could be is something server side, either with the workbook/embeded connections or the server itself.

    If I can confirm this to be the case, I will submit a PR with the fixed XML generators.

  5. added
    help wantedA user needs help, may be a mistake, a bug or a feature request
    on Jul 25, 2019
  6. irwando commented on Jul 25, 2019

    @irwando

    I believe this is built in behavior to server that would require extensive changes in our infrastructure. I'll follow up with some other teams.

  7. kir4h commented on Oct 5, 2020

    @kir4h

    Facing the same issue. As a workaround, I have included in a script some logic to create a temporary copy of the workbook that gets modified by using https://github.com/tableau/document-api-python, in order to align the datasource in the workbook with the one in the connection.

            source_wb = Workbook(file_path)
            for ds in source_wb.datasources:
                for conn in ds.connections:
                    conn.server = host
                    conn.port = port
                    conn.username = user

    where host, port and user represent the connection details for the datasource

    With these modifications, publishing works again in my scenario

  8. pavankumartableau commented on Nov 25, 2021

    @pavankumartableau

    I am also facing the same issue, let me know if anyone found any solution to this.
    Datasource of my Workbook connected to Dev database, I am just changing hostname to Prod while publishing.
    This is the error I see.

    image

  9. added
    document-apiFunctionality implemented in https://github.com/tableau/document-api-python
    and removed
    help wantedA user needs help, may be a mistake, a bug or a feature request
    on Oct 8, 2022
  10. jacalata commented on Feb 15, 2023

    @jacalata
    Contributor

    It's hard for me to follow what each person is doing here, and whether we're talking about published or embedded connections.

    In general, updating a connection is a different action to publishing a new connection.
    I think, from reading the tsc code, that it is broken and it attempts to use the publishing request format to update the connection. It needs to be updated so that it doesn't re-use this.

    To update the workbook connection, this is the API that tsc is calling: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_workbooks_and_views.htm#update_workbook_connection

    The request format is

    <tsRequest>
      <connection
        serverAddress="server-address" 
        serverPort="port"
        userName="connection-username" 
        password="connection-password"
        embedPassword="embed-password"
        queryTaggingEnabled="query-tagging-enabled" />
    </tsRequest>
    

    Publishing a workbook
    This request format is

      <workbook name="workbook-name" showTabs="show-tabs-flag" thumbnailsUserId="user-luid">
        <connections>
        <connection serverAddress="server-address" serverPort="port-number">
            <connectionCredentials 
                name="connection-username" password="connection-password" embed="embed-flag" />
        </connection>
        </connections>
        <project id="project-id"/>
      </workbook>
    
    
  11. removed
    document-apiFunctionality implemented in https://github.com/tableau/document-api-python
    on May 30, 2025
  12. github-actions commented on Aug 6, 2026

    @github-actions

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. If this is still relevant, please comment to keep it open.

  13. github-actions commented on Aug 21, 2026

    @github-actions

    Closing due to inactivity. If this is still relevant, please reopen or file a new issue.

  14. jacalata commented on Aug 25, 2026

    @jacalata
    Contributor

    Reopening — the stale bot auto-closed this earlier this month, and I owe the thread an updated take.

    On Publish Workbook, serverAddress in the <connections><connection> block is a match key — the server uses it to figure out which embedded connection in your uploaded file the credentials should attach to. It is not a directive to change the workbook's server address on publish. The workbook publishes with whatever server address is baked into the file.

    To change an embedded connection's server on publish, use two calls:

    1. POST /workbooks — Publish Workbook, with credentials in <connectionCredentials>.
    2. PUT /workbooks/{workbook-id}/connections/{connection-id} — Update Workbook Connection, with the new serverAddress.

    In TSC: Server.workbooks.publish(...) then Server.workbooks.update_connection(...).

    The real gap here is documentation — the Publish Workbook payload template shows serverAddress without explaining that it's a match key rather than an override, which has led everyone on this thread (myself included in 2020) to expect the opposite. I'll open a docs bug against the REST API reference.

    🤖 Generated with Claude Code

  15. github-actions commented on Oct 25, 2026

    @github-actions

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. If this is still relevant, please comment to keep it open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions