TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am finalizing a document. There are a few underfull vbox I just cannot figure out where they are. Sometimes it is easy to figure out which page is underfull vbox from the log file, but sometimes it is not so easy. Is there any easy way to visualize the underfull vbox just like the visualized little bar for an overfull hbox?

share|improve this question
How is it you find the page where the Underfull warning came from? – Mlazhinka Shung Gronzalez LeWy Jul 4 '11 at 18:02
up vote 16 down vote accepted

No. The messages in the log file are all you can use.

share|improve this answer
Thanks. That is what I though. Just hoped maybe someone more clever than me know a way to visualize it. – Yan Zhou Jun 19 '11 at 11:15
@Yan Zhou Indeed. Would also like to hear about it if there's a way. – N.N. Jun 19 '11 at 11:21

Well, I've found a way to show the undefull boxes in the pdf. Nothing is impossible with luatex!

The process is a bit convoluted, but it works (at least in my minimal examples). But let see first the results. This is a little example document I prepared which produces a couple of Underfull vboxes.

The example


\parskip=3mm plus 1mm
1--- \lipsum[11]

\noindent\vbox to 6cm{% This should cause underfull vbox
2--- \lipsum[48]\par
3--- \lipsum[66]

4-- \lipsum[75]

      \vbox to 1cm{% Another underfull vbox
        \vskip 1mm
        \vskip 2mm plus 1mm
                & Foo bar \     \hline
      Foobar    & \vbox{\hbox{Foo}\hbox{bar}}\\ % No underfull this time

5-- \lipsum[101]

Paragraphs marked with 2 and 3 are typeset in a \vbox too large, and the same for the first \vbox inside the table. lualatex complains:

$ grep Underfull example.log
Underfull \vbox (badness 5802) detected at line 13
Underfull \vbox (badness 1019) detected at line 25

And the result pdf shows how paragraphs 2 and 3 are too separated, because TeX had to stretch the \parskip between them to make them fill the \vbox.


The desired result

Now, I add a single line in the preamble of the above tex source:


After compiling again with lualatex, the new pdf shows the underfull vboxes in red:


How was it done

My first idea was to process from lua the log file generated by tex, and search for the "Underful vbox" messages, take note of the line number in which they happened and the hook into the process_input_buffer callback to insert at that line some kind of mark. I had some problems trying to implement this approach, so I asked for help.

In the end, I got convinced that this approach was unfeasible because LuaTeX does not provide callbacks to get the messages being written in the log, and in addition file.open and file.read cannot be safely used from lua to read toe log file because that file is open and TeX is writting in it at same time.

So I tried a different approach. I hooked into vpack_filter callback, which is called when TeX has material to be packed in a vertical box and it is about to start packing it. From lua I have the opportunity of examining that box (in fact the node list composing it), throw it, let it pass, or modify it by inserting, deleting or changing nodes, all before TeX start the actual packing.

So, from this function I call node.vpack which "emulates" what TeX is about to do, and returns the result of the packing and the badness value. So I can read this badness and decide if it is a "underfull vbox" (badness > 100). In this case I modify that list by inserting nodes which "push" the red color at the beginning and "pop" it at the end. I learned from the source code of chickenize package some nifty tricks to do so.

The code

This is the content of DetectUnderfull.lua file:

-- Code to change color borrowed and adapted from chickenize package
WHAT = node.id("whatsit")
COL = node.subtype("pdf_colorstack")
color_push = node.new(WHAT,COL)
color_pop = node.new(WHAT,COL)
color_push.stack = 0
color_pop.stack = 0
color_push.cmd = 1     -- replace cmd with command if using LuaTeX >= 0.76.0 
color_pop.cmd = 2      -- replace cmd with command if using LuaTeX >= 0.76.0 

function vertical_pack(h, grcode, tam, tipo, maxd)
  local g, b
  g,b = node.vpack(h, tam, tipo)
  if (b>100) then
    color_push.data="1 0 0 rg"
    h = node.insert_before(h,h,node.copy(color_push))
    h = node.insert_after(h,node.tail(h),node.copy(color_pop))
    return h
  return true

-- Install my filter into luatex callbacks
luatexbase.add_to_callback('vpack_filter', vertical_pack, 'vpack_filter')

Update: Thanks to uli for detecting a problem with LuaTeX 0.76.0, and to Paul Gessler for fixing it.

share|improve this answer
WOW! This is very nice! Next, a different color for overfull vboxes and underfull hboxes. :) – egreg Mar 13 '13 at 16:45
This would be a good addition for lua-visual-debug. This package already shows glues and penalties. – Qrrbrbirlbel Mar 13 '13 at 17:05
@JLDiaz With LuaTeX 0.76 from TeXLive 2013 I get: LuaTeX error DetectUnderfull.lua:8: You cannot set field cmd in a node of type whatsit. Does it still work for you? – uli Jan 23 '14 at 21:41
@JLDiaz I see the same behavior as uli with LuaTeX 0.76.0 from MikTeX 2.9. Any idea? – Paul Gessler Mar 26 '14 at 1:33
@uli I figured this out in case you're still looking. Replacing cmd in lines 8 and 9 of DetectUnderfull.lua with command fixed the issue for me. – Paul Gessler Mar 26 '14 at 1:41

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.