Converting a multi-tab XLSX to HTML causes DirectoryInfo exception

We have groupdocs conversion for java deployed in a docker container running in kubernetes. Anytime we try to convert a spreadsheet with more than one tab, it blows up with the below exception. This occurs everytime and with every version of the library that we’ve tried, starting with v23.2 to v25.9.

We are guessing it’s a permission issue becuase the same error does not occur when running locally on windows or in a unit test in VSCode. Problem is we have no idea which directory is causing this error or how to fix it.

Any idea which directory it would be trying to write to and which configuration we need to adjust and/or permission.

com.groupdocs.conversion.internal.c.a.pd.internal.ms.System.IO.l1p: DirectoryInfo was not created

                at com.groupdocs.conversion.internal.c.a.pd.internal.ms.System.IO.lt.lI(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.internal.c.a.pd.ADocument.lI(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.internal.c.a.pd.ADocument.save(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.internal.c.a.pd.Document.save(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.savers.pdf.PdfToWebSaver.saveDocument(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.savers.pdf.PdfToWebSaver.save(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.savers.Saver.save(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.documents.k.save(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.helpers.b.b(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.converting.operations.ToWebConversionOperation.execute(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.pipeline.f$1$1.a(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.converting.operations.ToPdfConversionOperation.execute(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.converting.operations.ConvertToPdfIfRequiredFromSpreadsheetOperation.execute(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.pipeline.f$1$1.a(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.converting.operations.RemoveCommentsOperation.execute(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.pipeline.f$1$1.a(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.converting.operations.PagesLimitOperation.execute(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.pipeline.f$1$1.a(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.converting.operations.ApplySpreadsheetLoadOptionsOperation.execute(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.pipeline.f$1$1.a(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.pipeline.e.execute(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.pipeline.h.a(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.pipeline.h.a(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.b.convert(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.Converter.convert(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

                at com.groupdocs.conversion.Converter.convert(Unknown Source) ~[groupdocs-conversion-25.9.jar:25.9]

@johnnyfunkypants

  • Is the Docker container running with a non-root user? If so, which user UID/GID is being used?
  • Are you explicitly setting the TempDirectory in GroupDocs via ConversionConfig.setTempDirectory()? If not, have you checked if the default temp path (e.g. /tmp) is writable in the container?
  • Does the Kubernetes pod have any security policies (e.g. readOnlyRootFilesystem, securityContext) that restrict writing to local directories?
  • Have you verified that /tmp (or the directory being used) exists and has write permissions inside the container at runtime?

Hello @johnnyfunkypants ,

Thank you for contacting us and for the detailed description of your issue.

In addition to the questions raised by our AI Agent, we would like to recommend that you verify whether there are any write restrictions on the /tmp directory and, if so, grant write access to it.

Alternatively, you may specify a custom temporary directory by using ConverterSettings.setTempFolder().

If this does not help resolve the issue, please share your spreadsheet file with us so that we can perform further investigation.

  • Yes, running as non-root. UID=1001
  • Yes, temp directory is set to /groupdocs/temp - yes, the path is writable
  • No, there are no secuirty policies in place that would restrict writing to local directories. I also tried toggling readOnlyRootFilesystem explicitly and neither true/false works
  • Yes, the temp path exists and has write permissions

I’ve also tried using /tmp as the temp path and it still fails.

Can you confirm in the code that it is indeed the temp path that it is trying to write to when this exception occurs?

I could share you a file, but every spreadsheet with multiple tabs fails, it’s very easy to reproduce.

@johnnyfunkypants ,

Just in case, please share the file and the code sample you are using for the conversion.

Based on the stack trace, it appears that the issue is most likely caused by one of our third-party libraries, and at the moment it is not clear which directory it is attempting to write the file to. By default, this should be the /tmp directory.

Therefore, we will need to perform additional investigation using your specific use case.

I’ve simplified our code, but it basically does the below with given file and desired extension. Note, when we convert the same file to PDF, it works fine. But when we try to convert to HTML, it blows up with the above exception.

I also attached the same file I’ve been using.
MultiTabTest.zip (9.0 KB)

    public byte[] convert(MultipartFile file, String extension) {
        ConvertOptions<?> convertOptions = FileType.fromExtension(extension).getConvertOptions();
        ConverterSettings settings = new ConverterSettings();
        settings.setTempFolder("/tmp");

        Supplier<InputStream> documentInputStreamSupplier = () -> {
            try {
                return file.getInputStream();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        };
        String detectedExtension = MediaUtils.detectExtension(documentInputStreamSupplier, file.getOriginalFilename());
        LoadOptions loadOptions = FileType.fromExtension(detectedExtension).getLoadOptions();

        try (Converter converter = new Converter(
                documentInputStreamSupplier,
                () -> loadOptions,
                () -> settings)) {
            final ByteArrayOutputStream output = new ByteArrayOutputStream();
            converter.convert(() -> output, convertOptions);
            return output.toByteArray();
        }
    }

Hello @johnnyfunkypants ,

As I understand it, you are encountering this issue only when converting from .xlsx to .html, or does it occur for any input document format when converting to .html?

Have you tried setting WebConvertOptions.setEmbedFontResources(true)?

In this case, no separate resources folder should be created, and this may temporarily resolve the issue while we continue our investigation.

That is correct, it’s only a problem when converting to HTML (so far anyway).

Looks like setEmbedFontResources was introduced in v25.12 (we’ve only tested up to v25.9), I’ll try updating to that version and see if it helps.

Setting WebConvertOptions.setEmbedFontResources(true) did not make a difference, same error.

@johnnyfunkypants ,

In that case, I will carry out additional investigation using your file and get back to you with the results as soon as possible.

Hello @johnnyfunkypants ,

Unfortunately, we were unable to reproduce this issue on our side when converting .xlsx to .pdf.

We also tried running the Docker container as a non-root user, but the issue did not reproduce.

If you are also using a Docker container, could you please share a small sample of your application along with the Dockerfile that reproduces this issue? This would help us speed up the investigation.

I’ll see what I can do, not sure how much I can share.

In the mean-time, are you able to list any directories that you know the libraries may be writing to (besides /tmp). I could at least look at those and make sure they exist and confirm they are writable.

As well, the exception itself is kind of weird, can you see in the code what exactly it’s trying to do when that exception occurs?

Hello @johnnyfunkypants ,

You do not necessarily need to use your own application. You may be able to reproduce this issue in your own Docker container using a simple Maven application that contains only a single conversion method. The main goal is for us to understand what differs in your use case.

Regarding what happens at the stage when the error occurs — the document is simply being re-saved using our third-party library.

I have created a ticket for this issue in our tracking system under ID CONVERSIONJAVA-3052 so that our development team can also investigate this use case.

I will get back to you as soon as I receive any feedback from them.

Below is the dockerfile we use to run our container.

# Define base image with Java and fonts
FROM eclipse-temurin:21.0.8_9-jre-alpine AS base

RUN apk update && apk add --no-cache ca-certificates && update-ca-certificates

## Install fonts
# See https://wiki.alpinelinux.org/wiki/Fonts

# Microsoft fonts
RUN apk add --no-cache fontconfig msttcorefonts-installer && update-ms-fonts
# Asiatic languages
RUN apk add --no-cache font-ipa \
    font-isas-misc \
    font-jis-misc \
    font-noto \
    font-noto-cjk \
    font-sony-misc
# Cyrillic languages
RUN apk add --no-cache font-cronyx-cyrillic \
    font-misc-cyrillic \
    font-mutt-misc \
    font-screen-cyrillic \
    font-vollkorn \
    font-winitzki-cyrillic
# Misc languages
RUN apk add --no-cache font-arabic-misc \
    font-noto-adlam \
    font-noto-arabic \
    font-noto-armenian \
    font-noto-bamum \
    font-noto-bengali \
    font-noto-buhid \
    font-noto-chakma \
    font-noto-cherokee \
    font-noto-devanagari \
    font-noto-emoji \
    font-noto-ethiopic \
    font-noto-extra \
    font-noto-georgian \
    font-noto-gujarati \
    font-noto-gurmukhi \
    font-noto-hebrew \
    font-noto-kannada \
    font-noto-kayahli \
    font-noto-khmer \
    font-noto-lao \
    font-noto-lisu \
    font-noto-malayalam \
    font-noto-myanmar \
    font-noto-nko \
    font-noto-olchiki \
    font-noto-oldturkic \
    font-noto-oriya \
    font-noto-osage \
    font-noto-sinhala \
    font-noto-tamil \
    font-noto-telugu \
    font-noto-thaana \
    font-noto-thai \
    font-noto-tibetan \
    font-noto-tifinagh \
    font-noto-vai

# Configure fonts
RUN fc-cache -f -v

FROM eclipse-temurin:21.0.8_9-jre-alpine AS builder

WORKDIR /application
# Copy all jars from the target directory because it is difficult to only copy the bundled jar
COPY target/*.jar ./
RUN rm -f ./*sources.jar ./*javadoc.jar
ARG JAR_FILE=*.jar
RUN mv ./${JAR_FILE} application.jar
# Explode the jar to take advantage of Spring layering
RUN java -Djarmode=layertools -jar application.jar extract

# Copy the individual layers into the application
FROM base

# Copy font-overrides into image
COPY src/main/resources/font-overrides/* /usr/font-overrides/

# Copy the individual layers into the application
WORKDIR /application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./

ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

Hello @johnnyfunkypants ,

Unfortunately, we were still unable to reproduce this issue using your Dockerfile and our test application.

As mentioned in my previous response, we will need any simple sample of your application that we can reliably run on our side to reproduce and confirm the issue by following your instructions.

I was able to find the offending code via debugging the stack trace I shared.

In the PdfToWebSaver, the saveDocument method has a hard-coded c:\fakepath in it. This results in the code trying to create a folder named c: in /application which ultimately fails in our linux environment. I was able to get around this by explicitly mounting a path in our container at /application/c:, it’s a horrible workaround but it works for now.

Would be happy if this could be fixed in GroupDocs, especially because it’s a path that only works nicely in Windows, and because it’s trying to write to a folder that is not documented and not in the configured temp folder.

private void saveDocument(Document var1, Stream var2) {
      HtmlSaveOptions var3 = this.getOptions(var1);
      var3.setCustomHtmlSavingStrategy(new 1(this));
      this._convertedStream = var2;
      var1.save("c:\\fakepath", var3);
}

image.png (6.9 KB)

Hello @johnnyfunkypants ,

Thank you for sharing the workaround with us. I also raised the question regarding the use of "c:\\fakepath" with our developers, and they confirmed that this behavior comes from the way our third-party library works. Since I was not able to reproduce this issue on my side initially, I could not be 100% certain that this was the root cause of the error. I have now forwarded this information to our developers, and they will try to address and fix it as soon as possible.

1 Like