Skip to content
This repository has been archived by the owner on Jan 2, 2023. It is now read-only.

Linux version cannot write on STDOUT when wkhtmltopdf used as a child-process. #3119

Open
miccarr opened this issue Sep 13, 2016 · 10 comments · May be fixed by #5023
Open

Linux version cannot write on STDOUT when wkhtmltopdf used as a child-process. #3119

miccarr opened this issue Sep 13, 2016 · 10 comments · May be fixed by #5023
Labels

Comments

@miccarr
Copy link

miccarr commented Sep 13, 2016

Hi,

When wkhtmltopdf is spawned as a child-process on linux (via a NodeJS app in my case, seems to have same problem on other languages), it cannot output to STDOUT by throwing :

QPainter::begin(): Returned false
Error: Unable to write to destination
Exit with code 1, due to unknown error.

When I do the same command (wkhtmltopdf whatever.html - like) on a shell, it works.

I don't have this problem on osX, only on Docker & Linux.

@miccarr
Copy link
Author

miccarr commented Sep 13, 2016

a workaround is to pipe the result to cat

like so : wkhtmltopdf whatever.html - | cat

@sleighter
Copy link

sleighter commented Oct 18, 2016

I am experiencing a very similar issue when attempting to use wkhtmltopdf from a Ruby application. The issue does not occur for my application when running in Heroku, but does appear when running the same application on Docker containers. In both cases the command works when writing the output to a file, but not when writing to STDOUT. Like miccarr, I can even pipe the output to less or cat and it's fine. But the way PDFKit uses wkhtmltopdf, the parent process (my application) is reading from the child process's STDOUT, which is unwritable by the child process, causing my PDFKit render calls to fail. The cat workaround would need to be implemented in PDFKit, so that's not a great option. Here are some details:

Heroku Dyno with Ruby Buildpack (working)

$ uname -a
Linux dyno-64c8158f-db3c-43a1-9466-50f078fb64ed 4.4.0-42-generic #62~14.04.1-Ubuntu SMP Fri Oct 7 23:15:48 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

$ wkhtmltopdf --version
Name:
  wkhtmltopdf 0.9.6

$ echo '<html><body><div>HELLO WORLD</div></body></html>' | wkhtmltopdf - -
Loading pages (1/5)
Resolving links (2/5)
Counting pages (3/5)
Printing pages (5/5)
%PDF-1.4=====================================================] Page 1 of 1
1 0 obj
<<
/Title (��)
/Producer (wkhtmltopdf)
/CreationDate (D:20161018172625)
>>
####  [File content truncated for clarity] ####

$ echo '<html><body><div>HELLO WORLD</div></body></html>' | wkhtmltopdf - - > somefile.pdf
Loading pages (1/5)
Resolving links (2/5)
Counting pages (3/5)
Printing pages (5/5)
Done

Docker Container (not-working)

$ uname -a
Linux fccb3d61-00d4-46dc-9ff8-8e07180d6bf8 3.13.0-92-generic #139-Ubuntu SMP Tue Jun 28 20:42:26 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

$ wkhtmltopdf --version
Name:
  wkhtmltopdf 0.9.6

$ echo '<html><body><div>HELLO WORLD</div></body></html>' | wkhtmltopdf - -
Loading pages (1/5)
QPainter::begin(): Returned false============================] 100%
Error: Unable to write to destination

$ echo '<html><body><div>HELLO WORLD</div></body></html>' | wkhtmltopdf - - > somefile.pdf
Loading pages (1/5)
Resolving links (2/5)
Counting pages (3/5)
Printing pages (5/5)
Done

In the Docker case, somefile.pdf is a valid PDF.

For reference, PDFKit is issuing this command, as copied from the application logs (again, works in Heroku, doesn't work in Docker):

/app/vendor/bundle/ruby/2.3.0/bin/wkhtmltopdf --orientation Landscape --quiet - -

The error message generated in Docker application logs is:

QPainter::begin(): Returned false
Error: Unable to write to destination
Exit with code 1, due to unknown error.

Seems to be the same issue reported in:
#2934
#2036
But those reporters abandoned the issue. Please let me know if I can provide additional information.

edit: formatting

@sleighter
Copy link

sleighter commented Oct 18, 2016

I have tried monkey patching PDFKit to append | cat to the wkhtmltopdf command. But this did not resolve the issue.
From the application logs:

RuntimeError (command failed: /app/vendor/bundle/ruby/2.3.0/bin/wkhtmltopdf --orientation Landscape --quiet - - | cat):

My issue may be a Docker issue. @miccarr, did you experience this issue on non-Dockerized Linux?

See moby/moby#11462

@lmars
Copy link

lmars commented Oct 19, 2016

@sleighter this doesn't work in Flynn due to flynn/flynn#3535, we'll work on a patch.

By the way, the | cat workaround works because cat writes directly to fd 1, whereas wkhtmltopdf instead uses /dev/stdout if it exists (see here), but that sometimes causes issues (e.g. in Flynn's case EACCES, and I suspect in other cases ENXIO if for example stdout is a socket which you can't use open(2) on).

@ghost
Copy link

ghost commented Feb 25, 2017

@sleighter @miccarr It is possible to use a container to pipe in and stream it back out. I think the main trick is the switches you pass when invoking docker run. I have a container that exposes only the wkhtmltopdf binary but had to pass something like:

docker run \
	--interactive \
	--attach \
	stdin \
	--attach \
	stdout \
	--attach \
	stderr \
	-e \
	DISPLAY=xvfb:99 \
	--link \
	xvfb \ # name of a container running xvfb 
	--quiet \
         my-wkhtmltopdf-container \
	--orientation \
	portrait \
	- - > test.pdf

Without the attach or interactive flags, I was unable to get the piping working.

@ROBERT-MCDOWELL
Copy link

as much as it sounds weird, I solved the same issue of yours I had with a simple exec() call with php by
adding sudo ..... 2>&1

@yakeer
Copy link

yakeer commented Jan 12, 2021

Facing the same issue.
.NET 5, Ubuntu 20.04

@MagicalTux
Copy link

strace output:

openat(AT_FDCWD, "/dev/stdout", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = -1 EACCES (Permission denied)

@MagicalTux
Copy link

MagicalTux commented Jun 9, 2021

It turns out /dev/stdout points to /proc/self/fd/1 which points to /dev/pts/0 if running into an interactive terminal (which can only be opened by the original terminal owner), or pipe:[102026296] if using a pipe (for example with cat).

@MagicalTux
Copy link

MagicalTux commented Jun 13, 2021

in src/lib/pdfconverter.cc line 347 replace:

         if (QFile::exists("/dev/stdout"))

with:

         if ((QFile::exists("/dev/stdout")) && (QFileInfo("/dev/stdout").isWritable()))

Should fix this issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Development

Successfully merging a pull request may close this issue.

7 participants