Troubleshooting MSSQL-Conf Setup: Resolving Python Module Errors in SQL Server

Table of Contents

Troubleshooting MSSQL-Conf Setup Python Errors

This article provides guidance and solutions for resolving errors encountered when attempting to execute the mssql-conf setup command on Microsoft SQL Server on Linux. Specifically, it addresses issues related to Python module dependencies that manifest when an older version of Python is installed on the system. Understanding the underlying requirements and implementing the correct workaround is crucial for successfully configuring SQL Server 2019 on various Linux distributions. This document will detail the symptoms, the root cause, and proven methods to overcome these compatibility challenges, ensuring a smooth setup process for your SQL Server instance.

Applies To

The information and solutions presented in this article are primarily applicable to:

  • SQL Server 2019 on Linux

Users working with this specific version of SQL Server on a Linux operating system may encounter the described Python-related issues during the initial configuration phase using the mssql-conf utility. While the core concepts of Python versioning and dependency management are universal, the specific errors and workarounds discussed here are confirmed for SQL Server 2019.

Symptoms

When attempting to initialize and configure Microsoft SQL Server 2019 on a Linux environment using the mssql-conf setup command, you may encounter errors if the system’s default Python 3 version is older than 3.5. These errors indicate a failure in loading necessary Python modules or accessing specific functions introduced in later Python versions. The most common manifestations are ImportError related to the typing module and AttributeError concerning the run method within the subprocess module.

A typical scenario involves installing SQL Server on a Linux distribution that ships with an older Python 3 version, such as Python 3.4. Following the standard installation procedures, you proceed to run /opt/mssql/bin/mssql-conf setup to accept the EULA, set the SA password, and configure the server edition. At this point, the execution halts with a traceback indicating a missing module.

One of the initial errors you might encounter is the ImportError: No module named 'typing'. This occurs because the typing module, which provides support for type hints, was added to the standard library in Python 3.5. The mssql-conf utility’s underlying Python scripts (mssqlad.py, pyadutil.py) rely on this module for static type checking or other internal mechanisms.

testslesvm2:~ # /opt/mssql/bin/mssql-conf setup
Traceback (most recent call last):
  File "/opt/mssql/bin/../lib/mssql-conf/mssql-conf.py", line 17, in <module>
    import mssqlad
  File "/opt/mssql/lib/mssql-conf/mssqlad.py", line 15, in <module>
    import pyadutil
  File "/opt/mssql/lib/mssql-conf/pyadutil.py", line 6, in <module>
    import typing
ImportError: No module named 'typing'

Even if you somehow manage to install the typing module separately (though it’s intended to be part of the standard library in 3.5+), or if the typing module is available but other Python 3.5+ features are missing, you may encounter a subsequent error. This error specifically points to a missing attribute on the subprocess module. The message AttributeError: 'module' object has no attribute 'run' indicates that the subprocess.run() function, a higher-level API for running subprocesses introduced in Python 3.5, is being called but is not available in the older Python version.

testslesvm2:~ # /opt/mssql/bin/mssql-conf setup
Warning: could not create log file for mssql-conf at /var/opt/mssql/log/mssql-conf/mssql-conf.log.
Traceback (most recent call last):
  File "/opt/mssql/bin/../lib/mssql-conf/mssql-conf.py", line 597, in <module>
    main()\
  File "/opt/mssql/bin/../lib/mssql-conf/mssql-conf.py", line 593, in main
    processCommands()\
  File "/opt/mssql/bin/../lib/mssql-conf/mssql-conf.py", line 310, in processCommands
    COMMAND_TABLE[args.which]()\
  File "/opt/mssql/bin/../lib/mssql-conf/mssql-conf.py", line 93, in handleSetup
    mssqlconfhelper.setupSqlServer(eulaAccepted, noprompt=args.noprompt)\
  File "/opt/mssql/lib/mssql-conf/mssqlconfhelper.py", line 964, in setupSqlServer
    if not checkInstall():\
  File "/opt/mssql/lib/mssql-conf/mssqlconfhelper.py", line 934, in checkInstall
    return runScript(checkInstallScript, runAsRoot) == 0\
  File "/opt/mssql/lib/mssql-conf/mssqlconfhelper.py", line 915, in runScript
    process = subprocess.run([pathToScript], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\
AttributeError: 'module' object has no attribute 'run'

Both error messages fundamentally point to the same underlying problem: the Python environment used by mssql-conf does not meet the minimum version requirement of Python 3.5. Recognizing these specific tracebacks is key to diagnosing the issue quickly.

Cause

The root cause of the ImportError for ‘typing’ and the AttributeError for subprocess.run is a fundamental incompatibility between the Python version available on your Linux system and the version required by the mssql-conf utility and its associated Python libraries. SQL Server 2019’s mssql-conf tool, which is written in Python, was developed with dependencies on features and modules introduced in Python 3.5 or later. Earlier versions of Python 3, such as 3.4, simply do not include these components in their standard library or provide the necessary functions.

Specifically, the typing module became part of the Python standard library in version 3.5 (though it was available as a backport via pip for older versions). Code using type hints (List, Dict, Union, etc.) or importing from the typing module directly will fail if typing is not present. Similarly, the subprocess.run() function was a significant addition in Python 3.5, offering a more unified and convenient way to execute external commands and capture their output compared to older methods like subprocess.call() or subprocess.Popen() followed by communicate(). The mssql-conf script utilizes subprocess.run() internally to execute helper scripts or system commands necessary for the configuration process.

When the Linux system defaults to a Python 3 interpreter older than 3.5 when executing mssql-conf.py, the interpreter encounters import statements for the typing module or calls to subprocess.run(). Since these features do not exist in Python 3.4 or earlier, the interpreter throws the respective ImportError or AttributeError, causing the mssql-conf setup command to fail prematurely before any meaningful configuration can take place. The dependency on Python 3.5+ is an inherent requirement of the SQL Server 2019 mssql-conf implementation on Linux.

Understanding Python Versioning and Dependencies

Python is a dynamically evolving language, with new features, modules, and improvements introduced in each release. Major and minor version updates often bring significant changes to the standard library and language syntax. Applications written in Python are typically developed against a specific version or range of versions, relying on the availability of certain features, functions, and modules within that version’s standard library or external dependencies.

In the context of system tools like mssql-conf, which interact closely with the operating system and other system services, the Python interpreter used is often the system’s default Python 3. Linux distributions vary in the Python versions they bundle. Older distributions might still provide Python 3.4 as the default Python 3 interpreter, while newer ones have transitioned to 3.6, 3.8, or later. This variability can lead to compatibility issues when installing applications like SQL Server that have specific Python version requirements for their tools.

Dependencies in Python can be external libraries installed via package managers like pip, or they can be modules that are part of Python’s standard library. The errors seen with mssql-conf involve modules that are expected to be in the standard library of a specific Python version (typing in 3.5+, subprocess.run function in 3.5+). When the system’s default Python is too old, these expected components are missing, leading to runtime errors. This highlights the importance of aligning the execution environment’s Python version with the application’s requirements.

Managing multiple Python versions on a single system is common practice, especially for developers. Tools like pyenv or simply installing different Python versions side-by-side and using symbolic links or environment variables can help. However, system-level scripts executed by administrative tools often rely on the default interpreter found in the system’s PATH. For mssql-conf, ensuring that the specific command execution environment points to a compatible Python 3.5+ interpreter is key. The subprocess.run() function, for example, was part of Python Enhancement Proposal (PEP) 324 and provided a much-needed improvement over the fragmented subprocess control methods that existed previously, justifying its adoption in newer Python code like that powering mssql-conf. Similarly, PEP 484 introduced type hints, and while not strictly necessary for code execution, the typing module contains objects used for defining these hints, and its presence in the standard library simplifies their usage, hence the dependency.

Workarounds

To successfully run mssql-conf setup and configure SQL Server 2019 when your Linux system has a Python 3 version older than 3.5, you have two primary workaround options. Both involve ensuring that a compatible Python 3.5+ interpreter is used when the mssql-conf command is executed.

Option 1: Upgrade the System’s Default Python 3

This involves upgrading the system’s primary Python 3 installation to version 3.5 or later. After the upgrade, you need to ensure that the /usr/bin/env python3 command, which is commonly used in scripts to locate the preferred Python 3 interpreter, points to the newly installed, newer version.

Pros: System-wide fix; mssql-conf and potentially other Python 3 scripts designed for newer versions will work without session-specific modifications.
Cons: This option carries a significant risk. Many Linux distributions rely on specific Python versions for core system utilities and package managers (like yum, dnf, apt, zypper). Upgrading or altering the system’s default Python installation can break these critical system components, potentially leading to an unstable or non-functional system. It is crucial to understand the dependencies of your distribution before attempting this.

Option 2: Create a Session-Specific Symlink (Soft Link) for Python 3

This is the recommended and safer approach. Instead of changing the system’s default Python, you create a symbolic link (symlink or soft link) within a specific directory. This symlink points from the name python3 to a newer Python 3.5+ executable that you have installed separately. You then modify the PATH environment variable for the current shell session to include the directory containing your symlink at the beginning of the path. This tricks the system into finding your desired Python 3.5+ executable when mssql-conf is run, as it searches directories in the PATH from left to right.

Pros: Much safer as it does not alter core system files or dependencies; the change is temporary and only affects the current shell session or sessions explicitly configured with the modified PATH.
Cons: The PATH modification needs to be reapplied every time you open a new shell session where you intend to run mssql-conf. However, this is a minor inconvenience compared to the risk of system instability with Option 1.

Given the risks associated with modifying the system’s default Python, the session-specific symlink method (Option 2) is the strongly preferred workaround for most users encountering this issue.

The session-specific symlink method allows you to provide a compatible Python 3.5+ environment for mssql-conf without disturbing the system’s default Python interpreter. Follow these steps carefully to implement this workaround.

Step 1: Install a Compatible Python Version (3.5 or later)

If you do not already have Python 3.5+ installed alongside your older system Python, you will need to install it. The method depends on your Linux distribution. For distributions using zypper (like SUSE Linux Enterprise Server, used in the original example):

sudo zypper in python36

This command installs Python 3.6. Replace python36 with the appropriate package name for the Python 3.5+ version available in your distribution’s repositories (e.g., python3.5, python3.6, python3.7, python3.8, etc., or simply python3 if it’s a newer distro). For distributions using apt (like Ubuntu, Debian): sudo apt update && sudo apt install python3.6 (adjust version as needed). For distributions using yum/dnf (like RHEL, CentOS, Fedora): sudo dnf install python36 or sudo yum install python36 (adjust version).

Step 2: Install SQL Server 2019

Ensure that you have already installed SQL Server 2019 on your Linux system. The setup commands vary slightly by distribution. For SUSE Linux Enterprise Server (SLES), the commands are typically:

sudo zypper addrepo -fc https://packages.microsoft.com/config/sles/12/mssql-server-2019.repo
sudo zypper --gpg-auto-import-keys refresh
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo zypper install -y mssql-server

This step should be completed successfully before attempting to run mssql-conf setup.

Step 3: Create the Symlink and Modify the PATH

You need to perform these actions in a shell session where you have root privileges, as mssql-conf setup requires root. Switch to the root user:

sudo su

Navigate to a directory where you can create the symlink. Your home directory (/root for the root user) is a convenient place, or any other temporary directory. Create a symbolic link named python3 that points to the executable of the newer Python version you installed in Step 1. For Python 3.6 located at /usr/bin/python3.6:

ln -s /usr/bin/python3.6 python3

This creates a file named python3 in your current directory that is a symbolic link to /usr/bin/python3.6. Next, modify the PATH environment variable for the current session. Add the current directory (. or $PWD) to the beginning of the PATH.

PATH=$(pwd):$PATH

This command takes the current working directory ($(pwd)), adds a colon (:) separator, and then appends the existing $PATH. By putting the current directory first, the shell will look for executables in the current directory before it looks in system directories like /usr/bin or /bin.

Verify that the symlink and PATH modification are working correctly by checking which python3 executable is found and its version:

which python3
/usr/bin/env python3 -V

The which python3 command should show the path to your symlink (e.g., /root/python3 if you created it in /root). The /usr/bin/env python3 -V command (which is how mssql-conf often invokes Python) should now output the version of the newer Python you linked (e.g., Python 3.6.15).

Step 4: Run mssql-conf Setup

With the PATH correctly configured in your root session, you can now run the mssql-conf setup command:

/opt/mssql/bin/mssql-conf setup

This command should now execute successfully using the Python 3.6 interpreter (or whichever version you linked), as it will be found first in the modified PATH. Follow the prompts to accept the license terms, set the SA password, and select the SQL Server edition.

Step 5: Reapply PATH for Future mssql-conf Commands

Remember that the PATH=$(pwd):$PATH command only affects the current shell session. If you close the session or open a new one, the PATH will revert to its default, and mssql-conf will again fail. To run mssql-conf again in the future (e.g., to change settings), you will need to repeat Step 3 in the new root session before executing any mssql-conf commands.

Alternatively, you could place the ln -s and PATH=$(pwd):$PATH commands in a simple script and execute that script before running mssql-conf, or add them to the root user’s shell profile file (~/.bashrc, ~/.profile) if you prefer a more permanent solution, but be cautious with system-wide profile changes.

Why Python 3.5+?

The dependency on Python 3.5 or newer for mssql-conf in SQL Server 2019 stems from the development choices made by the Microsoft engineering team. As mentioned, Python 3.5 introduced several features that enhance code quality, developer productivity, and potentially the robustness of applications.

The inclusion of the typing module in the standard library (PEP 484) allowed developers to add type hints to their code. While not strictly enforced at runtime by the default CPython interpreter, type hints enable static analysis tools (linters, type checkers like MyPy) to catch potential errors before runtime, improve code readability, and facilitate better tooling support in Integrated Development Environments (IDEs). Using type hints can lead to more maintainable and less error-prone code.

The subprocess.run() function (part of PEP 324 implementation) simplified the process of executing external commands. Prior to 3.5, developers often had to combine subprocess.Popen with communicate() or other methods to manage process input, output, and return codes, which could be verbose and sometimes tricky to handle correctly, especially concerning timeouts and error streams. subprocess.run() provides a single function call to achieve the most common patterns for running subprocesses, making the code cleaner and easier to write and read.

It is reasonable to assume that the developers of mssql-conf leveraged these newer Python features to improve the utility’s implementation. Consequently, users attempting to run this tool with Python versions lacking these features will encounter compatibility errors. This underscores the general principle that software has specific dependencies, and meeting those dependencies is essential for successful operation.

Best Practices and Long-Term Solutions

While the symlink workaround is effective for immediate use, it’s worth considering long-term strategies for managing Python versions on your system, especially if you plan to use other modern Python applications or develop Python code yourself.

Keeping your Linux distribution updated is the simplest way to eventually resolve this issue system-wide, as newer distribution releases will ship with more recent default Python 3 versions. However, upgrading a production server’s operating system is a significant undertaking and may not always be feasible or desirable solely for a Python dependency.

Understanding the End-of-Life (EOL) status of Python versions is also crucial. Python 3.4 has reached its EOL and no longer receives security updates. Running code on unsupported Python versions can expose you to security vulnerabilities. Microsoft’s requirement for Python 3.5+ aligns with the general move away from unsupported Python versions. For more details on Python’s lifecycle, you can consult resources like endoflife.date.

If you frequently need to run commands that require a newer Python version, consider setting up a dedicated directory for symlinks like the one described and adding that directory to the root user’s PATH permanently via their shell profile file (~/.bashrc or ~/.profile). However, exercise caution when modifying system-wide profile files, as incorrect changes can cause login issues. Always back up profile files before editing them.

For environments where multiple projects require different Python versions, advanced tools like pyenv can help manage installations and switch between versions more cleanly, though integrating this with system utilities requiring root might add complexity. For the specific case of mssql-conf, the session-specific symlink is often the most straightforward and safe approach.

Ultimately, the long-term solution involves ensuring that your system’s environment aligns with the requirements of the software you run. For SQL Server 2019 on Linux, this explicitly includes having a Python 3.5+ environment available for mssql-conf.

See Also

  • General documentation on installing and configuring SQL Server on Linux provides broader context beyond just the mssql-conf Python issue.
  • Information regarding Python versioning and the features introduced in Python 3.5 (such as the typing module and subprocess.run() function) can offer deeper insight into why these specific errors occur.
  • Resources detailing the End-of-Life status of Python versions highlight the importance of using supported language runtimes for security and stability.

This information is provided to help resolve a specific technical issue. While third-party links might be relevant for additional context (like Python’s EOL policy or distribution-specific package management), Microsoft provides this contact information for convenience and does not guarantee the accuracy of external sites.

Do you have questions about these workarounds or encounter different issues during your SQL Server on Linux setup? Share your experience and questions below!

Post a Comment