Week 3: Debugging
2026-04-29
statprog[@]stat.uni-muenchen.deThis week (Apr 30): Practical is directly after the Lecture
Practical will be on 30/04 at 12-2pm (c.t.) in room Schellingstr. 3 (S) / S 004
Oral exams are scheduled for Jul 30.
Part 1: Statistical Programming Foundations (W2–6)
| Part | What it does |
|---|---|
function(arg1, arg2 = default) |
declares the function and its inputs |
{ ... } |
body — the code that runs |
return(...) |
what the function hands back (optional) |
Tip
If there is no return(), R returns the value of the last expression.
Test on known inputs, then stress-test
Warning
R coerces types silently — wrong answers with no error are worse than a crash.
Validate inputs explicitly
stopifnot() — quick but blunt:
if / stop() — custom message:
“you gave me THIS, but I need THAT”
DRY → DRRY
Outside-In vs Inside-Out
Tip
If you struggle to name a function, it’s probably doing too many things.
We’ll be using the rAI learning space by aihorizon R&D. in the course — a web-based platform that gives you access to several state-of-the-art LLMs through one interface, including OpenAI’s GPT family (GPT-5.2, GPT-4o, o3-mini), Microsoft’s Phi and MAI models, and locally-hosted models. You can pick the model that fits each task.
We focus on using LLMs via chat-based interfaces, but these principles can also apply to other types of generative AI tools.
What sub-tasks and workflows are involved in a data science project?
What kind of inputs and outputs are involved in these tasks?
Imagine you had a team working on a data science project, what standards and processes might you need?
| Task abstraction | LLM concept |
|---|---|
| Project-wide instructions & guidelines | System-wide prompts |
| Setting and completing tasks | Prompts & conversations |
| Producing intermediate and final outputs | LLM-generated outputs |
| Evaluation and feedback | Tests and quality assurance |
| Scaling up / recruiting new team members | Agentic models; context & harness engineering |
You are responsible for LLM output — it can look correct and still be wrong.
Exact checks (for well-defined outputs)
Judgement checks (for open-ended outputs)
Tip
The same principle as function testing applies: verify on known inputs first, then stress-test edge cases.
A.1: LLMs were used in this project for…
Example answer
An LLM pipeline was used to generate multiple text variants with the same meaning of harmful online content inputs, including both clean and adversarial texts.
For each input, the LLM produced several paraphrased samples that preserve the original meaning. Predictions were obtained for both generated samples and the original input, then aggregated to produce the final prediction.
…
Review from StatProg1 & based on:
| Type | What happens | What to do | |
|---|---|---|---|
| 🚨 | Error | Code stops, no result | Must fix before continuing |
| ⚠️ | Warning | Code runs, result may be wrong | Inspect output carefully |
| 💬 | Message | Code runs, informational only | Read it — something may have changed |
Warning
Silent errors are worse than all three — code runs, result is wrong, no message at all. Always sense-check output against what you’d expect.
Variable doesn’t exist — typo, or earlier code not run.
Package not loaded — add library(dplyr).
sample$x — sample is a function, not your data frame.
Argument name doesn’t exist for this function — check ?log.
Required argument not supplied — check the function signature.
Not installed — run install.packages("pkg") first.
?function_name shows valid arguments, types, and examplesSession → Restart R or Cmd/Ctrl+Shift+F10)Tip
If you frequently struggle to locate errors, break long pipelines into named intermediate steps — easier to inspect and easier to debug.
Writing a good question helps others understand your problem — and often helps you find the solution yourself.
Good question
A good question should include a minimal reproducible example (MRE) of the problem. This allows others to run your code and encounter the issue you want help on.
Minimal
Reproducible
library() calls for any required packagesdput() to convert data to code if you must share real dataset.seed() if randomness is involveddput()structure(list(mpg = c(21, 21, 22.8, 21.4, 18.7, 18.1, 14.3,
24.4, 22.8, 19.2, 17.8, 16.4, 17.3, 15.2, 10.4, 10.4, 14.7, 32.4,
30.4, 33.9, 21.5, 15.5, 15.2, 13.3, 19.2, 27.3, 26, 30.4, 15.8,
19.7, 15, 21.4), cyl = c(6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8,
8, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 8, 6, 8, 4)), row.names = c("Mazda RX4",
"Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout",
"Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280",
"Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood",
"Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic",
"Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin",
"Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2",
"Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora",
"Volvo 142E"), class = "data.frame")
Use {reprex}
reprex::reprex()Tip
Writing a reprex often finds the bug for you — the act of making code self-contained reveals the missing library() or stale variable.
Course resources
AI tools
Community
[r] and the package nameTip
Answering questions on the forum (even imperfectly) is one of the best ways to consolidate your own understanding.
Based on:
You likely used the following strategies in StatProg 1:
{rainer} or other LLMs to ask for explanations of errorsprint()/cat()/message() inside your functionsDebugging tools
Just like a repair person has tools for diagnosing and fixing issues with machines, there are also specialised tools for debugging code!
traceback() and rlang::last_trace()browser()debug() and debug_once()Traceback shows the call sequence leading up to an error — useful for understanding where in nested code the error occurred.
Calls
A call is an invocation of a function — every time you write f(x), R executes f and records that invocation on the call stack. The stack grows as functions call other functions, and unwinds as they return. The traceback is also known as the call stack, stack trace, or backtrace.
When you encounter an error, you can use traceback() or rlang::last_trace() to get location information about the error.
traceback() (base R)
4: stop("something went wrong!")
3: h(x)
2: g(x)
1: f(1)
rlang::last_trace() (tidyverse)
Backtrace:
▆
1. └─global::f(1)
2. └─global::g(x)
3. └─global::h(x)
Tip
If you use tidyverse packages, prefer rlang::last_trace() — it filters out internal calls and shows a cleaner tree. Use traceback() for base R errors or when rlang is not available.
print() to browser()print() debugging — scatter calls, re-run, clean up
Tip
browser() gives you the full environment at once — no need to guess which variable to print next.
At Browse[1]> you can inspect x, y, run any expression, or step line by line.
browser()Insert browser() anywhere in a function body
browser()At the pause you see Browse[1]>. Key commands:
| Command | Action |
|---|---|
n |
execute next line |
s |
step into next function call |
f |
finish current loop or function |
c |
continue normal execution |
Q |
Quit debugger |
RStudio highlights the next line to run in the editor, shows current variables in the Environment pane, and the call stack in the Traceback pane.
debug() and debugonce()For functions you don’t want to modify (e.g. from packages), use debug() or debugonce() instead of inserting browser().
debug(fn) — triggers on every call until undebug(fn)
Tip
Prefer debugonce() — debug() can trap you in the debugger if the function is called internally many times.
With Quarto, errors can occur outside the R session — in YAML, file paths, or the rendering pipeline.
Common causes
:)@fig-xxx with no matching label)Strategies
quarto render in the terminal — more verbose than the RStudio Render buttonexecute: error: true to let code chunks fail without halting the renderTip
YAML indentation errors are the most common: use spaces (not tabs), and check every level lines up correctly.
Warning
LLMs are fluent, not accurate. A wrong answer written confidently is still wrong.
{reprex} to format it[r]), Posit Community| Goal | Tool |
|---|---|
| Locate where the error occurred | traceback(), rlang::last_trace() |
| Pause and inspect inside your function | browser() |
| Debug a package function without editing it | debugonce(fn), debug(fn) |
| Debug outside R (YAML, paths, render) | quarto render in terminal |
This week (Apr 30): Practical is directly after the Lecture
Practical will be on 30/04 at 12-2pm (c.t.) in room Schellingstr. 3 (S) / S 004