Suggestions for resolving FoundationNetworking Error when static linking on Linux/Docker?

I have a small bit of code (from a dependency) that used to work, but seems to have broken as part of updates to my docker setup (updating to use swift 5.7 nightly toolchain with static linking) and I'm not sure how to resolve it after discussing on the Vapor Discord.

The code looks like the following (from dependency):

do {
  data = try Data(contentsOf: sanitizedSchemeUrl)
} catch {
  return .failure(.internalError(reason: error.localizedDescription))
}

and the top of the file includes the following import:

#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

Now, when calling this code inside of a docker container I get the following error:

Foundation/NSSwiftRuntime.swift:409: Fatal error: You must link or load module FoundationNetworking to load non-file: URL content using String(contentsOf:…), Data(contentsOf:…), etc.

For reference, the full docker file looks as follows:

# ================================
# Build image
# ================================
FROM swiftlang/swift:nightly-5.7-focal as build

# Install dependencies - do this before build for improved docker caching
# 1. libcurl4-openssl-dev needed for libcurl/ccurl commands in app
# 2. libssl-dev required by libcurl4-openssl-dev
# 3. cleanup after apt process
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
  && apt-get -q update \
  && apt-get -q dist-upgrade -y \
  && apt-get -q -y install \
  libcurl4-openssl-dev \
  libssl-dev \
  libxml2-dev \
  && rm -rf /var/lib/apt/lists/*

# Set /app as working directory
WORKDIR /build

# Add the ssh key used to clone private dependencies from github
ARG SSH_PRIVATE_KEY
RUN mkdir /root/.ssh/
RUN echo "${SSH_PRIVATE_KEY}" | base64 -d > /root/.ssh/id_rsa
RUN touch /root/.ssh/known_hosts
RUN ssh-keyscan github.com >> /root/.ssh/known_hosts
RUN chmod 0600 /root/.ssh/id_rsa

# First just resolve dependencies.
# This creates a cached layer that can be reused
# as long as your Package.swift/Package.resolved
# files do not change.
COPY ./Package.* ./
RUN swift package resolve

# Copy everything from the build directory to docker's working directory
COPY . .

# Build everything, with optimizations
# -g enables debug info in compiled executable
# -Xswiftc passes flag through to all swift compiler invocations
# -c release => build with configuration release
RUN swift build -c release --static-swift-stdlib
#RUN --mount=type=cache,target=/code/.build swift build -c release (for caching builds in non-release configurations)

# Switch to the staging area
WORKDIR /staging

# Copy main executable to staging area
RUN cp "$(swift build --package-path /build -c release --show-bin-path)/Run" ./

# Copy resources bundled by SPM to staging area
RUN find -L "$(swift build --package-path /build -c release --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \;

# Copy any resouces from the public directory and views directory if the directories exist
# Ensure that by default, neither the directory nor any of its contents are writable.
RUN [ -d /build/Public ] && { mv /build/Public ./Public && chmod -R a-w ./Public; } || true
RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w ./Resources; } || true

# ================================
# Run image
# ================================
FROM ubuntu:focal

# Make sure all system packages are up to date.
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
  && apt-get -q update \
  && apt-get -q dist-upgrade -y \
  && apt-get -q install -y \
  ca-certificates \
  tzdata \
  libxml2 \
  libcurl4 \
  && rm -r /var/lib/apt/lists/*
    
# Create a vapor user and group with /app as its home directory
RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor

# Need to learn what these do
ARG env
ENV env ${env:-production}

ARG GIT_HASH=undefinedHash
ARG GIT_TAG=undefinedTag
ARG GIT_BRANCH=undefinedBranch

ENV GIT_HASH=$GIT_HASH
ENV GIT_TAG=$GIT_TAG
ENV GIT_BRANCH=$GIT_BRANCH

# Sets working directory to /app
WORKDIR /app

# Copy built executable and any staged resources from builder
COPY --from=build --chown=vapor:vapor /staging /app

# Ensure all further commands run as the vapor user
USER vapor:vapor

# Let Docker bind to port 8080
EXPOSE 8080

ENTRYPOINT ["./Run"]
CMD ["serve", "--env", "$env", "--hostname", "0.0.0.0", "--port", "8080", "--auto-migrate"]

Any help is greatly appreciated.

2 Likes
# ================================
# Run image
# ================================
FROM ubuntu:focal

# Make sure all system packages are up to date, and install only essential packages.
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
    && apt-get -q update \
    && apt-get -q dist-upgrade -y \
    && apt-get -q install -y \
      ca-certificates \
      tzdata \
      openssl \
      libssl-dev \
      unzip \
      zip \
      libzip-dev \
      libplist3 \
# If your app or its dependencies import FoundationNetworking, also install `libcurl4`.
      libcurl4 \
# If your app or its dependencies import FoundationXML, also install `libxml2`.
      libxml2 \
    && rm -r /var/lib/apt/lists/*

Since my English is not good, I can only provide part of my configuration. You can try the above code if it solves your problem

1 Like

@jsam can you create an issue on GitHub - apple/swift: The Swift Programming Language ideally with reproduction steps and a project if possible then I can make sure it gets routed to the right person to look at

1 Like

@jsam if you have created issue on Github, can you please share a link, so I can follow a topic. I have same situation
When I run swift app under the clean Vapor, it is all good, but soon as it is run under the docker env... it is complaining for:
Foundation/NSSwiftRuntime.swift:409: Fatal error: You must link or load module FoundationNetworking to load non-file: URL content using String(contentsOf:…), Data(contentsOf:…), etc.

Also, if you found a solution to this issue, share it : ))

Thank you

Update on my case:
Foundation/NSSwiftRuntime.swift:409: Fatal error: You must link or load module FoundationNetworking to load non-file: URL content using String(contentsOf:…), Data(contentsOf:…), etc.

This error was due to the wrong installation of Swift on Ubuntu ... now it is all good... up and working.

Could you provide more details on this please? Did you use a different image for Swift on Ubuntu or resolved the issue in some other way?

Hi @Max_Desiatov

Sorry for not being precise and clear,

Wrong installation of Swift on Ubuntu

I messed here a lot regarding the Swift installation on Ubuntu, I did something wrong, not sure what I've messed, but after reinstallation all is good
Current setup for Swift version / Ubuntu on my server playground:

  • Swift version 5.6.3 (swift-5.6.3-RELEASE), Target: x86_64-unknown-linux-gnu
  • Linux Mint 20.3 Cinnamon version 5.2.7

Hope situation is clearer and hope it helps
Cheers
:beers:

Is this issue reproducible for you with official Swift Docker images though, as reported by the OP?

My answer would be yes, because I was modifying Dockerfile

# If your app or its dependencies import FoundationNetworking, also install `libcurl4`.
      libcurl4 \
# If your app or its dependencies import FoundationXML, also install `libxml2`.
      libxml2 \

I can setup again tmrw again and let you know if you need this info?

This helped me a lot:

Did you use --static-swift-stdlib flag when building, as specified by the OP? In my testing with swift:5.6-focal image everything works fine with (default) dynamic linking, but produces the same NSSwiftRuntime.swift error when --static-swift-stdlib is passed to swift build. libcurl4 is installed, but that doesn't fix the error.

Yes, in Dockerfile:

swift build -c release --static-swift-stdlib

And for testing, I did a setup with supervisorctl, and my .sh for this is quite simple setup:

swift build --configuration release

Share what you have found / discovered : )
Really interested
Tnx

Yo, update from my tests, I gave you wrong informations, I had duplicated processes on server,
Not working with:

swift build -c release --static-swift-stdlib