> ## Documentation Index
> Fetch the complete documentation index at: https://resources.latex-cloud-studio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# LaTeX Warnings Explained: Overfull hbox, Underfull hbox, Badness 10000

> Understand what Overfull \hbox, Underfull \hbox (badness 10000), and Float(s) lost actually mean, which ones you can safely ignore, and how to fix the ones that matter.

export const RenderedOutput = ({title = "Rendered output", ctaHref, ctaLabel = "Open LaTeX Cloud Studio", children}) => {
  const [isExpanded, setIsExpanded] = useState(false);
  const trackEditorCta = () => {
    const target = new URL(ctaHref, window.location.href);
    globalThis.posthog?.capture?.("docs_app_cta_clicked", {
      source_page: window.location.pathname,
      source_section: "rendered_output",
      cta_variant: "first_compiled_example",
      target_url: target.toString(),
      target_utm_source: target.searchParams.get("utm_source"),
      target_utm_medium: target.searchParams.get("utm_medium"),
      target_utm_campaign: target.searchParams.get("utm_campaign"),
      target_utm_content: target.searchParams.get("utm_content")
    }, {
      transport: "sendBeacon",
      send_instantly: true
    });
  };
  return <details className="rendered-output" onToggle={event => setIsExpanded(event.currentTarget.open)}>
      <summary className="rendered-output__summary">
        <span className="rendered-output__title">{title}</span>
        <span className="rendered-output__hint" aria-hidden="true">View compiled result</span>
      </summary>
      {isExpanded && <div className="rendered-output__content">
          {children}
          {ctaHref && <aside className="rendered-output__cta" aria-label="Continue in the LaTeX editor">
              <span>
                <strong>Ready to use this syntax?</strong>
                Continue in the browser editor when you want to adapt the example in a real project.
              </span>
              <a href={ctaHref} onClick={trackEditorCta}>{ctaLabel}<span aria-hidden="true"> →</span></a>
            </aside>}
        </div>}
    </details>;
};

export const LatexSource = ({filename, source}) => {
  const [copyStatus, setCopyStatus] = useState("Copy");
  const copySource = async () => {
    try {
      await navigator.clipboard.writeText(source);
      setCopyStatus("Copied");
    } catch {
      setCopyStatus("Select and copy");
    }
  };
  return <figure className="latex-source">
      <figcaption className="latex-source__header">
        <span className="latex-source__filename">{filename}</span>
        <button type="button" className="latex-source__copy" onClick={copySource} aria-live="polite">
          {copyStatus}
        </button>
      </figcaption>
      <pre className="latex-source__pre" aria-label={`LaTeX source: ${filename}`} tabIndex="0">
        <code className="language-latex">{source}</code>
      </pre>
    </figure>;
};

export const LatexPreview = ({src, alt, caption, width, height}) => {
  const minZoom = 1;
  const maxZoom = 3;
  const zoomStep = 0.5;
  const measureSvgContent = async (assetSrc, pageWidth, pageHeight) => {
    const cacheKey = "__latexCloudSvgContentBoxCache";
    const contentBoxCache = globalThis[cacheKey] ?? new Map();
    globalThis[cacheKey] = contentBoxCache;
    if (contentBoxCache.has(assetSrc)) return contentBoxCache.get(assetSrc);
    const measurement = (async () => {
      const assetUrl = new URL(assetSrc, window.location.href);
      if (assetUrl.origin !== window.location.origin) {
        throw new Error("Rendered output must use a same-origin SVG asset.");
      }
      const response = await fetch(assetUrl, {
        credentials: "same-origin"
      });
      if (!response.ok) throw new Error(`Rendered output request failed with ${response.status}.`);
      const source = await response.text();
      const documentNode = new DOMParser().parseFromString(source, "image/svg+xml");
      if (documentNode.querySelector("parsererror")) throw new Error("Rendered output is not valid SVG.");
      const sourceSvg = documentNode.documentElement;
      sourceSvg.querySelectorAll("script, foreignObject").forEach(node => node.remove());
      [sourceSvg, ...sourceSvg.querySelectorAll("*")].forEach(node => {
        [...node.attributes].forEach(attribute => {
          if ((/^on/i).test(attribute.name)) node.removeAttribute(attribute.name);
          if ((attribute.name === "href" || attribute.name === "xlink:href") && !attribute.value.startsWith("#")) {
            node.removeAttribute(attribute.name);
          }
        });
      });
      const measurementHost = document.createElement("div");
      measurementHost.className = "latex-preview__measurement-host";
      const measuredSvg = document.importNode(sourceSvg, true);
      measuredSvg.setAttribute("aria-hidden", "true");
      measurementHost.appendChild(measuredSvg);
      document.body.appendChild(measurementHost);
      try {
        const measuredElements = [...measuredSvg.children].filter(node => !["defs", "desc", "metadata", "style", "title"].includes(node.tagName.toLowerCase()));
        const elementBounds = measuredElements.map(node => node.getBBox()).filter(box => [box.x, box.y, box.width, box.height].every(Number.isFinite) && box.width > 0 && box.height > 0);
        if (elementBounds.length === 0) {
          throw new Error("Rendered output has no measurable visible content.");
        }
        const sortedBounds = [...elementBounds].sort((left, right) => left.y - right.y);
        const clusterGap = pageHeight * 0.045;
        const clusters = [];
        sortedBounds.forEach(box => {
          const current = clusters[clusters.length - 1];
          if (!current || box.y - current.bottom > clusterGap) {
            clusters.push({
              boxes: [box],
              bottom: box.y + box.height
            });
            return;
          }
          current.boxes.push(box);
          current.bottom = Math.max(current.bottom, box.y + box.height);
        });
        const contentClusters = clusters.filter(cluster => {
          const clusterBox = cluster.boxes.reduce((combined, box) => {
            const right = Math.max(combined.x + combined.width, box.x + box.width);
            const bottom = Math.max(combined.y + combined.height, box.y + box.height);
            const x = Math.min(combined.x, box.x);
            const y = Math.min(combined.y, box.y);
            return {
              x,
              y,
              width: right - x,
              height: bottom - y
            };
          });
          const centerY = clusterBox.y + clusterBox.height / 2;
          const isMarginFurniture = cluster.boxes.length <= 2 && clusterBox.width < pageWidth * 0.2 && clusterBox.height < pageHeight * 0.04 && (centerY < pageHeight * 0.08 || centerY > pageHeight * 0.8);
          return !isMarginFurniture;
        });
        const visibleBounds = (contentClusters.length > 0 ? contentClusters : clusters).flatMap(cluster => cluster.boxes);
        const bounds = visibleBounds.reduce((combined, box) => {
          const right = Math.max(combined.x + combined.width, box.x + box.width);
          const bottom = Math.max(combined.y + combined.height, box.y + box.height);
          const x = Math.min(combined.x, box.x);
          const y = Math.min(combined.y, box.y);
          return {
            x,
            y,
            width: right - x,
            height: bottom - y
          };
        });
        const clampValue = (value, minimum, maximum) => Math.min(maximum, Math.max(minimum, value));
        const padding = Math.max(8, Math.min(pageWidth, pageHeight) * 0.025);
        const x = clampValue(bounds.x - padding, 0, pageWidth);
        const y = clampValue(bounds.y - padding, 0, pageHeight);
        const right = clampValue(bounds.x + bounds.width + padding, 0, pageWidth);
        const bottom = clampValue(bounds.y + bounds.height + padding, 0, pageHeight);
        return {
          x,
          y,
          width: right - x,
          height: bottom - y
        };
      } finally {
        measurementHost.remove();
      }
    })();
    contentBoxCache.set(assetSrc, measurement);
    measurement.catch(() => contentBoxCache.delete(assetSrc));
    return measurement;
  };
  const renderPreviewAsset = ({contentBox: assetContentBox, loading}) => {
    if (!assetContentBox) {
      return <img className="latex-preview__asset" src={src} alt={alt} width={width} height={height} loading={loading} draggable="false" />;
    }
    return <svg className="latex-preview__asset" viewBox={`${assetContentBox.x} ${assetContentBox.y} ${assetContentBox.width} ${assetContentBox.height}`} preserveAspectRatio="xMidYMid meet" role="img" aria-label={alt}>
        <image href={src} x="0" y="0" width={width} height={height} />
      </svg>;
  };
  const [isOpen, setIsOpen] = useState(false);
  const [frameMode, setFrameMode] = useState("content");
  const [viewMode, setViewMode] = useState("fit");
  const [zoom, setZoom] = useState(minZoom);
  const [contentBox, setContentBox] = useState(null);
  const [measurementStatus, setMeasurementStatus] = useState("loading");
  const dialogRef = useRef(null);
  const closeButtonRef = useRef(null);
  const viewportRef = useRef(null);
  const previousFocusRef = useRef(null);
  const dragRef = useRef(null);
  useEffect(() => {
    let isCurrent = true;
    setMeasurementStatus("loading");
    measureSvgContent(src, width, height).then(box => {
      if (!isCurrent) return;
      setContentBox(box);
      setMeasurementStatus("ready");
    }).catch(() => {
      if (!isCurrent) return;
      setContentBox(null);
      setFrameMode("page");
      setMeasurementStatus("error");
    });
    return () => {
      isCurrent = false;
    };
  }, [height, src, width]);
  const closeViewer = useCallback(() => {
    setIsOpen(false);
  }, []);
  const openViewer = () => {
    previousFocusRef.current = document.activeElement;
    setFrameMode(contentBox ? "content" : "page");
    setViewMode("fit");
    setZoom(minZoom);
    setIsOpen(true);
  };
  const applyZoom = useCallback(nextZoom => {
    const boundedZoom = Math.min(maxZoom, Math.max(minZoom, nextZoom));
    setViewMode("custom");
    setZoom(boundedZoom);
  }, []);
  const zoomIn = useCallback(() => {
    applyZoom(viewMode === "fit" ? minZoom + zoomStep : zoom + zoomStep);
  }, [applyZoom, viewMode, zoom]);
  const zoomOut = useCallback(() => {
    applyZoom(viewMode === "fit" ? minZoom : zoom - zoomStep);
  }, [applyZoom, viewMode, zoom]);
  useEffect(() => {
    if (!isOpen) return undefined;
    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    closeButtonRef.current?.focus();
    return () => {
      document.body.style.overflow = previousOverflow;
      previousFocusRef.current?.focus?.();
    };
  }, [isOpen]);
  useEffect(() => {
    if (!isOpen) return undefined;
    const handleKeyDown = event => {
      if (event.key === "Escape") {
        event.preventDefault();
        closeViewer();
        return;
      }
      if ((event.key === "+" || event.key === "=") && !event.metaKey && !event.ctrlKey) {
        event.preventDefault();
        zoomIn();
        return;
      }
      if (event.key === "-" && !event.metaKey && !event.ctrlKey) {
        event.preventDefault();
        zoomOut();
        return;
      }
      if (event.key !== "Tab" || !dialogRef.current) return;
      const focusable = [...dialogRef.current.querySelectorAll('button:not([disabled]), a[href], [tabindex]:not([tabindex="-1"])')];
      if (focusable.length === 0) return;
      const first = focusable[0];
      const last = focusable[focusable.length - 1];
      if (event.shiftKey && document.activeElement === first) {
        event.preventDefault();
        last.focus();
      } else if (!event.shiftKey && document.activeElement === last) {
        event.preventDefault();
        first.focus();
      }
    };
    window.addEventListener("keydown", handleKeyDown);
    return () => {
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [closeViewer, isOpen, zoomIn, zoomOut]);
  const startDrag = event => {
    if (event.button !== 0 || !viewportRef.current) return;
    const viewport = viewportRef.current;
    dragRef.current = {
      pointerId: event.pointerId,
      x: event.clientX,
      y: event.clientY,
      scrollLeft: viewport.scrollLeft,
      scrollTop: viewport.scrollTop
    };
    viewport.setPointerCapture(event.pointerId);
    viewport.dataset.dragging = "true";
  };
  const continueDrag = event => {
    const drag = dragRef.current;
    const viewport = viewportRef.current;
    if (!drag || !viewport || drag.pointerId !== event.pointerId) return;
    viewport.scrollLeft = drag.scrollLeft - (event.clientX - drag.x);
    viewport.scrollTop = drag.scrollTop - (event.clientY - drag.y);
  };
  const stopDrag = event => {
    const viewport = viewportRef.current;
    if (viewport?.hasPointerCapture(event.pointerId)) viewport.releasePointerCapture(event.pointerId);
    if (viewport) delete viewport.dataset.dragging;
    dragRef.current = null;
  };
  const activeContentBox = frameMode === "content" ? contentBox : null;
  const activeWidth = activeContentBox?.width ?? width;
  const activeHeight = activeContentBox?.height ?? height;
  const activeRatio = activeWidth / activeHeight;
  const inlineContentBox = measurementStatus === "ready" ? contentBox : null;
  const inlineWidth = inlineContentBox?.width ?? width;
  const inlineHeight = inlineContentBox?.height ?? height;
  const inlineGeometry = {
    aspectRatio: `${inlineWidth} / ${inlineHeight}`,
    maxWidth: `${30 * inlineWidth / inlineHeight}rem`
  };
  const imageStyle = viewMode === "fit" ? {
    aspectRatio: `${activeWidth} / ${activeHeight}`,
    width: "100%",
    maxWidth: `${Math.max(16, activeRatio * 78)}dvh`
  } : {
    aspectRatio: `${activeWidth} / ${activeHeight}`,
    width: `${zoom * 100}%`,
    maxWidth: "none"
  };
  const zoomLabel = viewMode === "fit" ? frameMode === "content" ? "Fit content" : "Full page" : `${Math.round(zoom * 100)}%`;
  return <figure className="latex-preview">
      <button type="button" className="latex-preview__trigger" onClick={openViewer} aria-haspopup="dialog" aria-label={`Open zoomable preview: ${alt}`}>
        <span className="latex-preview__page" style={inlineGeometry}>
          {measurementStatus === "loading" ? <span className="latex-preview__loading" role="status">Preparing compiled output…</span> : renderPreviewAsset({
    src,
    alt,
    width,
    height,
    contentBox: inlineContentBox,
    loading: "lazy"
  })}
        </span>
        <span className="latex-preview__trigger-label" aria-hidden="true">
          <span className="latex-preview__trigger-icon">⌕</span>
          Open viewer
        </span>
      </button>
      <figcaption className="latex-preview__caption">
        <span>
          {caption}
          {measurementStatus === "error" && <span className="latex-preview__status" role="status"> Content fit is unavailable; the complete vector page is shown.</span>}
        </span>
        <a href={src} target="_blank" rel="noreferrer" className="latex-preview__source-link">Open SVG</a>
      </figcaption>

      {isOpen && <div className="latex-preview__backdrop" onMouseDown={event => {
    if (event.target === event.currentTarget) closeViewer();
  }}>
          <section ref={dialogRef} className="latex-preview__dialog" role="dialog" aria-modal="true" aria-label={`Rendered LaTeX viewer: ${alt}`}>
            <header className="latex-preview__toolbar">
              <div className="latex-preview__identity">
                <span className="latex-preview__eyebrow">Compiled LaTeX</span>
                <span className="latex-preview__filename">{alt}</span>
              </div>
              <div className="latex-preview__controls" aria-label="Preview controls">
                <button type="button" className={frameMode === "content" && viewMode === "fit" ? "is-active" : undefined} disabled={!contentBox} onClick={() => {
    setFrameMode("content");
    setViewMode("fit");
    setZoom(minZoom);
  }}>
                  Fit content
                </button>
                <button type="button" className={frameMode === "page" && viewMode === "fit" ? "is-active" : undefined} onClick={() => {
    setFrameMode("page");
    setViewMode("fit");
    setZoom(minZoom);
  }}>
                  Full page
                </button>
                <span className="latex-preview__zoom-group">
                  <button type="button" onClick={zoomOut} disabled={viewMode === "fit" || zoom <= minZoom} aria-label="Zoom out">−</button>
                  <output aria-live="polite" aria-label="Current zoom">{zoomLabel}</output>
                  <button type="button" onClick={zoomIn} disabled={viewMode !== "fit" && zoom >= maxZoom} aria-label="Zoom in">+</button>
                </span>
                <a href={src} target="_blank" rel="noreferrer">Open SVG</a>
                <button ref={closeButtonRef} type="button" className="latex-preview__close" onClick={closeViewer} aria-label="Close rendered LaTeX viewer">
                  Close
                </button>
              </div>
            </header>
            <div ref={viewportRef} className="latex-preview__viewport" data-view-mode={viewMode} onPointerDown={startDrag} onPointerMove={continueDrag} onPointerUp={stopDrag} onPointerCancel={stopDrag}>
              <span className="latex-preview__dialog-page" style={imageStyle}>
                {renderPreviewAsset({
    src,
    alt,
    width,
    height,
    contentBox: activeContentBox
  })}
              </span>
            </div>
            <footer className="latex-preview__viewer-note">
              Compiler-generated vector output · Use +/− to zoom · Drag to pan · Esc to close
            </footer>
          </section>
        </div>}
    </figure>;
};

LaTeX warnings are not errors. Your document still compiles and produces a PDF. They
are TeX telling you it made a layout compromise, and some of those compromises are
visible on the page while others are invisible and safe to ignore.

This page explains what the most common messages mean in plain language, so you can
tell the difference.

## Which warnings actually matter

| Message                           | Visible in the PDF?                      | Act on it?                            |
| --------------------------------- | ---------------------------------------- | ------------------------------------- |
| `Overfull \hbox (Xpt too wide)`   | Usually yes — text runs into the margin  | Yes, if X is more than a point or two |
| `Underfull \hbox (badness 10000)` | Sometimes — wide word gaps               | Only if the spacing looks wrong       |
| `Underfull \vbox`                 | Sometimes — content spread down the page | Only if the page looks wrong          |
| `Float(s) lost`                   | Yes — a figure or table vanishes         | Always                                |
| `There were undefined references` | Yes — `??` in the text                   | Always                                |
| `Label(s) may have changed`       | No                                       | No, just recompile                    |

## Overfull \hbox

```bash overfull-warning.log theme={null}
Overfull \hbox (15.58524pt too wide) in paragraph at lines 42--45
```

TeX could not break a line within the text width, so the line sticks out past the
right margin by the amount shown. A value under about 2pt is usually invisible.
Anything larger normally is visible.

The usual causes are a long unbreakable item: a URL, a code identifier, a chemical
name, or a wide equation or table.

### Find it first

Compile with the `draft` class option. LaTeX draws a black bar in the margin next to
every overfull box, which is far faster than reading line numbers out of the log.

<LatexSource filename="find-overfull.tex" source={"\\documentclass[draft]{article}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This is setup or structural LaTeX code. It changes available commands or document behavior, but it does not produce meaningful standalone page content by itself.
  </Info>
</RenderedOutput>

### Fix it

For long words and URLs, let TeX hyphenate them. The `url` package breaks URLs at
sensible points, and `microtype` reduces overfull boxes across the whole document by
subtly adjusting character widths and spacing.

<LatexSource filename="fix-overfull.tex" source={"\\usepackage{microtype}\n\\usepackage{url}\n\n% Allow breaks inside a specific long word\nlong\\-word\\-that\\-needs\\-breaking\n\n% Teach TeX a hyphenation pattern for a word it gets wrong\n\\hyphenation{data-base bio-in-for-mat-ics}"} />

<RenderedOutput title="Rendered output" ctaHref="https://app.latex-cloud-studio.com/?utm_source=resources&utm_medium=rendered_output&utm_campaign=docs_open_app&utm_content=learn_latex_troubleshooting_warnings_explained">
  <LatexPreview src="/images/rendered/learn-latex-troubleshooting-warnings-explained-02/page-1.svg" alt="Compiled PDF page 1 from fix-overfull.tex" caption="Generated from the shown source with pdfLaTeX in the pinned LaTeXCloud TeX Live 2026 environment. The visible fragment is compiled inside the documented minimal article wrapper." width={595.276} height={841.89} />
</RenderedOutput>

If a single stubborn paragraph resists, `\sloppy` tells TeX to prefer wide word gaps
over running into the margin. Scope it to the paragraph rather than the document, or
you trade overfull boxes for ugly spacing everywhere.

<LatexSource filename="sloppy-scoped.tex" source={"\\begin{sloppypar}\nParagraph containing the awkward unbreakable content.\n\\end{sloppypar}"} />

<RenderedOutput title="Rendered output">
  <LatexPreview src="/images/rendered/learn-latex-troubleshooting-warnings-explained-03/page-1.svg" alt="Compiled PDF page 1 from sloppy-scoped.tex" caption="Generated from the shown source with pdfLaTeX in the pinned LaTeXCloud TeX Live 2026 environment. The visible fragment is compiled inside the documented minimal article wrapper." width={595.276} height={841.89} />
</RenderedOutput>

Wide tables and equations need a different fix: see
[advanced tables](/learn/latex/tables/advanced-tables) and
[breaking long equations](/learn/latex/mathematics/align-and-multline-environments).

## Underfull \hbox and badness 10000

```bash underfull-warning.log theme={null}
Underfull \hbox (badness 10000) in paragraph at lines 88--91
```

This is the message that confuses people most, because nothing looks broken.

**Badness measures how far TeX had to stretch the spaces to fill a line.** It runs
from 0 (perfect) to 10000, and 10000 means "infinitely bad" — TeX gave up and
stretched the spaces as far as it needed to. It is a complaint about spacing quality,
not a sign of a broken document.

Badness 10000 is by far the most common value because it is the ceiling. Seeing it
does not mean the problem is severe; it means the problem hit the maximum on the
scale.

### Common causes

* `\\` used to force a line break in ordinary text. The forced short line must be
  stretched to full width. This is the single most frequent cause.
* `\raggedright`, or a narrow column such as a `minipage` or a two-column layout.
* A paragraph where TeX chose stretched spaces over an overfull line.

### Fix it

If the spacing looks fine in the PDF, ignore it. That is a legitimate decision, not
laziness — the warning is advisory.

If it does look wrong, in body text use a blank line for a new paragraph rather than
`\\`:

<LatexSource filename="forced-break.tex" source={"% Causes Underfull \\hbox: forces a short line\nFirst line of text \\\\\nSecond line of text\n\n% Correct: a paragraph break\nFirst line of text\n\nSecond line of text"} />

<RenderedOutput title="Rendered output">
  <LatexPreview src="/images/rendered/learn-latex-troubleshooting-warnings-explained-04/page-1.svg" alt="Compiled PDF page 1 from forced-break.tex" caption="Generated from the shown source with pdfLaTeX in the pinned LaTeXCloud TeX Live 2026 environment. The visible fragment is compiled inside the documented minimal article wrapper." width={595.276} height={841.89} />
</RenderedOutput>

To silence the warnings from deliberately ragged text, tell TeX not to complain:

<LatexSource filename="ragged-no-warnings.tex" source={"\\usepackage{ragged2e}\n\\RaggedRight   % ragged right, with hyphenation and no badness warnings"} />

<RenderedOutput title="Expected effect">
  <Info>
    This is setup or structural LaTeX code. It changes available commands or document behavior, but it does not produce meaningful standalone page content by itself.
  </Info>
</RenderedOutput>

To relax TeX's standards document-wide, raise the tolerance. `\emergencystretch`
gives TeX extra room on a final pass rather than lowering quality everywhere:

<LatexSource filename="tolerance.tex" source={"\\setlength{\\emergencystretch}{3em}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This is setup or structural LaTeX code. It changes available commands or document behavior, but it does not produce meaningful standalone page content by itself.
  </Info>
</RenderedOutput>

## Underfull \vbox

The vertical equivalent: TeX stretched the spacing between elements to fill a page.

It usually appears near a page break where a float, a heading, or a `\clearpage` left
material that could not fill the page. If the page looks acceptable, ignore it. If
not, adjusting float placement is normally the real fix — see
[float and placement issues](/learn/latex/troubleshooting/float-and-placement-issues).

## Float(s) lost

```bash floats-lost.log theme={null}
LaTeX Warning: Float(s) lost on input line 120.
```

This one is never safe to ignore. A figure or table has been silently dropped and
will not appear in the PDF at all.

It happens when a float is declared somewhere TeX cannot move it out of — floats must
be able to migrate to the top or bottom of a page, and inside a box there is nowhere
to migrate to. The usual culprits are a `figure` or `table` environment placed inside:

* a `minipage`, `\parbox`, or `\fbox`
* another float
* a footnote

The closely related error `! LaTeX Error: Not in outer par mode` has the same root
cause and is thrown in the same situations.

### Fix it

Move the float to the top level of the document. If you genuinely need a captioned
figure inside a `minipage`, do not use the `figure` environment — use `\captionof`
from the `caption` package, which produces a caption without creating a float:

<LatexSource filename="captionof.tex" source={"\\usepackage{caption}\n\n\\begin{minipage}{0.45\\textwidth}\n  \\centering\n  \\includegraphics[width=\\linewidth]{plot.pdf}\n  \\captionof{figure}{A caption without creating a float}\n  \\label{fig:plot}\n\\end{minipage}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

For two figures side by side, `subcaption` handles the common case properly:

<LatexSource filename="subfigure.tex" source={"\\usepackage{subcaption}\n\n\\begin{figure}[htbp]\n  \\begin{subfigure}{0.45\\textwidth}\n    \\includegraphics[width=\\linewidth]{left.pdf}\n    \\caption{Left panel}\n  \\end{subfigure}\n  \\hfill\n  \\begin{subfigure}{0.45\\textwidth}\n    \\includegraphics[width=\\linewidth]{right.pdf}\n    \\caption{Right panel}\n  \\end{subfigure}\n  \\caption{Both panels}\n\\end{figure}"} />

<RenderedOutput title="Expected effect">
  <Info>
    This excerpt depends on project files such as images, bibliography data, or included TeX sources that are not part of this standalone code box. Its exact output is project-specific, so no fabricated preview is shown.
  </Info>
</RenderedOutput>

## Undefined references and changed labels

```bash reference-warnings.log theme={null}
LaTeX Warning: There were undefined references.
LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.
```

LaTeX resolves cross-references by writing them to an `.aux` file on one pass and
reading them back on the next. On the first compile the labels do not exist yet.

`Label(s) may have changed` simply means run it again. `There were undefined
references` after a second run means a `\ref` or `\cite` points at a label that does
not exist — check for a typo, or a `\label` placed before its `\caption`.

Cloud compilers usually handle the repeated passes for you. For citations, see
[bibliography build errors](/learn/latex/troubleshooting/bibliography-build-errors).

## Reading the log yourself

Warnings name the input line, which is the fastest way to find the source:

```bash grep-warnings.sh theme={null}
# Every warning and overfull box, with line numbers
grep -nE "Warning|Overfull|Underfull" main.log

# Just the ones that are usually visible
grep -nE "Overfull \\\\hbox \([0-9]{2,}" main.log
```

That second command filters to overfull boxes of 10pt or more, which is a practical
way to skip the noise and find the ones a reader would actually notice.

## Related Pages

* [Fixing compilation errors](/learn/latex/how-to/fixing-compilation-errors)
* [Float and placement issues](/learn/latex/troubleshooting/float-and-placement-issues)
* [Compiler and engine errors](/learn/latex/troubleshooting/compiler-and-engine-errors)
* [Troubleshooting center](/learn/latex/troubleshooting)

## Start in LaTeX Cloud Studio

<CardGroup cols={2}>
  <Card title="Open in LaTeX Cloud Studio" icon="cloud" href="https://app.latex-cloud-studio.com/?utm_source=resources&utm_medium=card&utm_campaign=docs_open_app&utm_content=warnings_explained_open_app">
    Compile in the browser and read the full log next to your source.
  </Card>

  <Card title="Troubleshooting center" icon="wrench" href="/learn/latex/troubleshooting">
    Work through the other common failure modes.
  </Card>
</CardGroup>
