2  Asking Technical Questions

Prerequisites: none. This chapter stands on its own.

See also: Chapter 3, Chapter 6, Chapter 35, Chapter 25, Chapter 26.

Purpose

Awesome-Awkward Penguin Meme: Work Up The Nerve To Ask For Help, Question Closed For Lack Of A MRE.

You’ve been stuck on an error for an hour. You finally give in and post in the course forum: “My code doesn’t work, can anyone help?” Two hours later someone replies, “What error are you getting?” You paste a screenshot. The next reply asks to see the code. Then which version of pandas you have. By the time the conversation gets anywhere, a whole day has gone by, and the fix turns out to be one line.

If that has happened to you, you’re in good company. Nobody sits you down and teaches you how to ask for help with code; it’s part of the hidden curriculum that everyone is expected to pick up somehow. The people who seem to get fast answers aren’t smarter or better connected. They’ve learned to hand the helper what the helper needs up front, so the conversation starts at the answer instead of at twenty questions. And that skill is learnable in an afternoon.

This chapter is that afternoon: a repeatable way to turn “it doesn’t work” into a question someone can answer, how to shrink your problem into a small example anyone can run, where to ask and what each place expects, and what to do once you have your answer. It doesn’t cover the full craft of hunting down bugs (that’s Chapter 6) or reading error messages line by line (Chapter 7), and it touches AI assistants only as far as they help you ask (Chapter 35 has the rest).

Why read this chapter

  • You posted “it doesn’t work, any ideas?” in the class Discord, and the only reply was “what’s the error?”
  • Your first Stack Overflow question was closed within the hour for needing “details or clarity,” and you have no idea which details they wanted.
  • You spent two hours stuck before going to office hours, where the TA spotted the problem in thirty seconds, and you’d like to know when to stop grinding and ask.
  • Someone told you to “post an MRE,” and you’re not sure how to shrink a 60-cell notebook into anything minimal.
  • A classmate’s fix worked perfectly on their laptop and did nothing on yours, and it turned out you were running a different Python.
  • You asked how to write a regex and got a regex, when one line of pandas would have done the whole job.
  • You want to use an AI assistant to help you get unstuck without pasting your API key or someone’s private data into a chat window.

Running theme: make your question runnable

The best thing you can do for a technical question is make it possible for someone else to see exactly what you saw, without guessing. Good questions aren’t longer; they’re better organized, and every line removes a guess.

2.1 A mental model of technical help

When you ask for help, you’re not asking someone to read your mind. You’re inviting them into a small investigation, and like any investigation it runs on three things. There’s the claim: what you expected to happen and what you saw instead. There’s the evidence: the smallest set of steps, code, and output that shows the claim is true. And there’s the context: the computer, versions, and constraints that decide which fixes will actually work for you.

Leave any of those out, and your helper has to ask for it before they can start. That’s normal, and nobody will think less of you for it, but every round trip costs you hours when people answer in between classes. You don’t need to impress anyone with vocabulary. You just need to supply the claim, the evidence, and the context, so the investigation can start with the first reply.

Why “help me” fails

Most questions that go nowhere fail in one of a handful of predictable ways, and it helps to recognize them in your own drafts.

The most common is an ambiguous symptom: “it doesn’t work,” without ever saying what working would have looked like. Close behind it are missing reproduction steps, where there’s no sequence of actions another person could follow to make the same thing happen on their machine. Then there’s no stated expectation: the helper can’t tell whether the program is misbehaving or whether you expected the wrong thing. Some questions have no evidence at all (no error message, no output, no code) and leave the helper to guess. Others have the opposite problem, too much irrelevant detail, like a whole notebook pasted in with no hint of where it fails, so the three lines that matter are buried under three hundred that don’t. And some land in the wrong channel, like a request for a half-hour debugging session in a chat meant for quick questions.

The good news is that every one of these has a direct, mechanical fix, and the rest of this chapter is about applying them.

2.2 Before you ask: a short self-debugging loop

Asking for help early is fine. Asking before you’ve looked at the problem at all is what gets people a cool reception, because the first three replies will be things you could have checked yourself. Five to fifteen minutes of structured poking around usually does two things: it sometimes solves the problem outright, and when it doesn’t, it gives you the raw material of a good question. Chapter 6 turns this into a full method; the loop below is the minimum version.

The 10-minute triage

Run through this list before you ask. It’s a checklist on purpose: you’ll use it when you’re frustrated, and that’s not the moment for paragraphs.

  1. Re-run once. Some problems come from stale state, like a notebook whose cells ran out of order, and vanish on a clean run.

  2. Reduce scope. Can you make the same error happen in a smaller script or a single notebook cell?

  3. Read the error. All of it, and copy it exactly rather than paraphrasing it.

  4. Find the first line that’s yours. A stack trace is often full of lines from inside the library; the line from your own file is usually where to start looking (Chapter 7 walks through this).

  5. Check recent changes. What did you change last? It worked yesterday, so what’s different today?

  6. Search with precision. Use the error message and the library name, not a description of your feelings about them.

  7. Consult the official docs. Look up the function you’re calling and check what it expects.

  8. Try one hypothesis. Change one thing, run it again, and see what happens.

  9. Write down what you tried. This becomes part of your question.

  10. Stop when you’re looping. If you’re trying the same thing for the third time, it’s time to ask.

That last step matters as much as the others. Grinding for another hour on something a TA could spot in a minute isn’t virtue; it’s an hour you don’t get back. The loop’s real job is to give you the facts a helper needs: what triggers the problem, what doesn’t, and what you’ve already ruled out.

What counts as “what I tried”

“What I tried” is one of the most useful parts of any question, but only when it’s made of concrete actions and what happened. “I checked that the file exists with ls data/input.csv, and it’s there.” “I printed df.dtypes and date is str, not datetime64.” “I ran pip install package==1.2.3 and the error changed from ModuleNotFoundError to ImportError: cannot import name 'foo'.” Each of those tells your helper something about the state of your computer and crosses off a possibility.

Compare “I tried a bunch of things” or “I looked online but nothing worked.” Those feel like proof of effort, but they carry no information, so your helper will cheerfully suggest the exact things you already tried. If you can’t remember what you tried, that’s the sign to start writing it down as you go, even in a scratch text file.

2.3 The anatomy of a good technical question

Nearly every strong technical question, whatever it’s about, fills in the same five fields:

  1. Goal: what you’re trying to do.

  2. Expected: what you expected to happen.

  3. Actual: what actually happened.

  4. Reproduction: the smallest steps, code, and data that make it happen.

  5. Context: your computer, your versions, and any constraints.

That structure works for Python errors, spreadsheet formulas, Git conflicts, missing files, and even “I don’t understand this concept.” The subsections below take the fields one at a time.

Goal

State your goal in one sentence built around a verb and an object: “Load a CSV into pandas and parse the date column.” “Connect to the lab server over SSH and run JupyterLab.” “Merge my feature branch into main without losing my changes.” Each names an outcome your helper can recognize as success.

This field matters more than people expect, because sometimes the best answer isn’t “here’s how to fix that error” but “there’s a much easier way to do what you actually want.” If your helper only sees the symptom, say a regex that won’t match, they’ll help you fix the regex, when the real answer might be that a regex is the wrong tool (see Chapter 18, and the XY problem below). Saying the goal keeps that door open.

Expected vs. actual

Always say both what you expected and what you got. It sounds obvious, but it’s the part people skip most, and without it your helper can’t tell a bug from a misunderstanding:

Expected: the date column converted to dates, so I can group by month.

Actual: ValueError: time data "2026/13/01" doesn't match format "%Y/%m/%d"

Notice that “expected” isn’t a guess about what the library does; it’s what you intended your program to do. And notice that the actual error, pasted exactly, already holds a clue. pd.to_datetime guessed a year/month/day format from the first row, then hit a row claiming month 13. Either that row is a typo, or the file writes some dates as year/day/month. A helper can see that in seconds, but only if you paste the real message.

Reproduction

Here’s the heart of it: if you can make the problem happen reliably, you can almost always solve it, and if someone else can make it happen on their computer, they can usually help you in minutes. A complete reproduction has four parts. There’s the exact command you ran, including which folder you were in. There’s the code that triggers the problem. There’s the input data, either the real file or a small made-up version with the same structure. And there’s the output or traceback, pasted as text rather than a screenshot:

$ pwd
/Users/alex/projects/q3-analysis
$ python load.py
Traceback (most recent call last):
  File "/Users/alex/projects/q3-analysis/load.py", line 4, in <module>
    df["date"] = pd.to_datetime(df["date"])
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
  ...
ValueError: time data "2026/13/01" doesn't match format "%Y/%m/%d". You might want to try:
    - passing `format` if your strings have a consistent format;
    ...

The ... lines mark where the book trimmed pandas’ internal frames to save space; in a real question, paste the whole thing. That kind of block (folder, command, and output, all as text) is what makes a question reproducible.

Context

Context is whatever decides whether a suggested fix will actually work on your machine. The details that come up most are your operating system (Windows, macOS, or Linux); your Python version and the environment you’re working in (conda, venv, or the system Python); the versions of the packages involved; any hardware limits that matter, like memory or a GPU; whether you have administrator rights on the computer; and whether you’re working locally or on a remote server.

You don’t need every one of those every time. Give enough to rule out the big categories of problem, and your helper will ask if they need more. For Python problems, a few short commands answer most of the questions a helper would otherwise ask, and “How much context is enough?” below shows them.

2.4 Minimal reproducible examples (MREs)

A minimal reproducible example, or MRE, is the most powerful tool you have for getting help. It’s a tiny, self-contained program that shows your problem and nothing else. You’ll also see it called a “minimal working example” or a “reprex.”

If “post an MRE” sounds like homework somebody assigns to get rid of you, here’s the secret: building one is also one of the best debugging techniques there is. Stripping a problem down to ten lines forces you to understand which parts matter, and a surprising number of times the bug reveals itself halfway through. It’s the same effect as rubber duck debugging, where explaining your code line by line to a toy duck on your desk makes the mistake jump out at you. Many questions never get posted, because the MRE answered them.

What “minimal” means

“Minimal” doesn’t mean tiny at all costs; it means nothing irrelevant. An MRE includes only what’s needed to trigger the problem. If your notebook has 50 cells but the error happens in one function call, your MRE might be a ten-line script that imports the same library, builds a small input, and calls that function.

Three ways to build an MRE

The first way is deletion. Start with your real code and delete pieces, running it after each cut. Every deletion that still fails proves the part you removed didn’t matter. The last version that still fails is your MRE. This is fast when the failing code is short.

The second way is construction. Start from a blank script and add pieces back until the error appears. It’s slower, but it tells you exactly which line is the trigger: the one whose addition flipped the script from working to broken. Use it when your code is too big to delete your way through, or when you want an airtight story about cause and effect.

The third way is substitution. Replace your real data with a few rows of made-up data that have the same structure. This one is essential when the real data is huge, private, or messy enough that you can’t share it. pandas will happily read a CSV from a string wrapped in io.StringIO, so a few inline rows are usually enough:

import pandas as pd
from io import StringIO

raw = """name,age,joined
Ada,35,2026/01/15
Lin,42,2026/13/01
"""
df = pd.read_csv(StringIO(raw))
df["joined"] = pd.to_datetime(df["joined"])   # reproduces the ValueError

Anyone with pandas installed can paste that and see the same ValueError you did. Most real MREs use all three moves together: you delete the code that doesn’t matter, swap in made-up data, and end up with a 15-line script that runs anywhere.

A template for MREs

This shape works for most Python questions. Here it’s filled in for the date problem above; swap in the library and the call you’re asking about:

# mre.py
import sys
import platform
import pandas as pd  # replace with the library you're asking about

print("Python:", sys.version)
print("Platform:", platform.platform())
print("pandas:", pd.__version__)

# minimal input
x = pd.Series(["2026/01/15", "2026/13/01"])

# reproduce
result = pd.to_datetime(x)
print(result)

The three print lines at the top report your Python version, your operating system (via Python’s platform module), and the library’s version. Delete them when versions clearly don’t matter, but keep them when they might; version mismatches are behind a lot of “works for me” mysteries.

2.5 How much context is enough?

Most students swing between too little context and far too much. When you can’t decide, use this rule:

Include anything a helper would need to run the same steps and see the same output.

If you’re not sure whether something matters, include it once and let the replies tell you what to trim.

Environment context: the “three lines”

Here’s a confusion that eats hours: you install a package, the install says it succeeded, and import still says ModuleNotFoundError. Almost every time, it’s because your computer has more than one Python, and the one running your code isn’t the one pip installed into. Three short answers settle it: which version of Python is running, where that Python lives (which tells you which environment it belongs to), and which version of the package that Python can see.

python --version
python -c "import sys; print(sys.executable)"
python -c "import pandas; print(pandas.__version__)"

The middle line prints the full path of the interpreter (sys.executable): if it points somewhere you didn’t expect, like the system Python instead of your project’s environment, you’ve probably found your problem (see Chapter 15). On macOS or Linux, which python gives the same answer. On Windows, where python works in Command Prompt, but in PowerShell where means something else entirely, so use Get-Command python there, or just stick with the sys.executable line, which works everywhere. If you use conda, conda list pandas shows the installed version too. (pip show pandas also reports a version, but for some packages, pandas included, it prints the package’s entire license along with it.) And if a Mac tells you python: command not found, try python3; recent versions of macOS don’t come with a plain python command.

Add one more line if the operating system might matter, python -c "import platform; print(platform.platform())", and paste all four outputs at the bottom of your question. Your helper now has nearly everything they’d otherwise have to ask for.

File system context

“File not found” might be the single most common error students ask about, and it’s rarely what it sounds like. The file usually exists. Python is just looking for it somewhere else, because relative paths are resolved from your working directory, the folder your program was started from, and that’s often not the folder you think. So when an issue involves a missing file, paste three things: the folder you’re in, the path your code uses, and a listing that shows where the file really is.

$ pwd
/Users/alex/projects/q3-analysis/notebooks
$ ls ../data | head
input.csv
metadata.json
$ python -c "import pandas; pandas.read_csv('data/input.csv')"
Traceback (most recent call last):
  ...
FileNotFoundError: [Errno 2] No such file or directory: 'data/input.csv'

Paste exactly that, and the answer is almost immediate: you’re inside notebooks/, the file is in ../data/, so the path needs the ../ in front, or you need to cd up one level first. Chapter 10 explains paths and working directories properly.

2.6 Choosing the right channel

Where you ask shapes what a good question looks like. A quick message to a teammate, a question at office hours, and a public post read by strangers all have different norms, and matching the norm is half of getting a useful answer.

In class and office hours

Face to face with an instructor or TA, the bar is lower than on a public forum, but the same preparation pays off. Bring your MRE and the exact text of the error, say what you’ve already tried (so the first ten minutes aren’t spent suggesting it), and be ready to reproduce the problem live on your laptop. And remember that office hours aren’t just for bugs. They’re one of the best places to untangle a concept you only half understand, or to ask whether your whole approach makes sense. An open-ended question is welcome, as long as it’s specific enough to have a useful answer.

Teammates

Your teammates are as busy as you are, so make it easy for them to help. Write a short problem statement before you ping them. Make it possible to help without a meeting: link to the failing line, paste the error, and summarize what you tried. And don’t drop a whole repository on them with no hint about where to look. The smaller the piece of code you ask them to hold in their head, the faster they can help.

Issue trackers

If your course or team uses GitHub Issues or another bug tracker, treat an issue as a question that leaves a written record. Future readers, including future you, will be glad of the structure. Start with the title: it should identify the problem at a glance, like pd.read_csv loads a semicolon-separated file as one column, not something that could describe a hundred problems, like read_csv broken. Paste code and errors as code blocks (three backticks on the lines before and after) so they keep their formatting. An issue is the right place when a bug affects more than one person, when the answer should be kept instead of disappearing into a chat scroll, or when fixing it will take follow-up work someone needs to track.

Public forums

Public forums like Stack Overflow, GitHub Discussions, or your course Discord can be enormously helpful, and they have norms worth respecting. Show that you’ve investigated, so volunteers aren’t sorting through hundreds of “does anyone know” posts. Include a real MRE, not a description of one. Give the post a clear, specific title. And never share sensitive data: API keys and passwords (see Chapter 34), real student records, or anything covered by privacy law such as FERPA, HIPAA, or the GDPR. If you’re a beginner, don’t worry about using the perfect terminology; most communities forgive that easily. Do worry about reproducibility and clarity, because those decide whether your question gets answered or scrolls away unanswered.

2.7 Searching and asking on Stack Overflow

Stack Overflow is the biggest collection of solved programming problems on the internet, and most of what it can do for you involves reading, not posting. It also has a reputation for being tough on newcomers, and if your first question got a chilly reception, you’re far from the only one. Most of that chill comes from a handful of site norms nobody explains up front. Learn them, and the site becomes much friendlier.

Searching first

Most of the time, someone has already asked your question. Finding their post takes the same precision you’d put into a question title, and three habits make the biggest difference.

Search for the error message, minus the parts that are yours. A traceback like KeyError: 'date' searches better as pandas KeyError column: the 'date' is specific to your data, but the rest is the general shape of the bug. If you paste the entire message, file paths and all, you’ll often get nothing, because nobody else has your exact folders and variable names.

Filter by tag. Tags on Stack Overflow work like topic filters, and the site’s search syntax lets you put a tag in square brackets: [pandas] to_datetime ValueError searches only questions tagged pandas. That’s the difference between wading through JavaScript answers and finding the three pandas posts that apply. Quotes work too, for an exact phrase.

Read the top-voted answer, not just the accepted one. The accepted answer is the one the original asker marked as solving their problem, sometimes a decade ago, and it may be out of date now. Votes reflect the judgment of everyone who came after. Check the dates: a recent answer that mentions a deprecation warning is more trustworthy than a 2014 answer written for a version of the library you don’t have.

When the site’s own search is noisy, try a web search with site:stackoverflow.com in front of your query. Google’s ranking sometimes finds the right post faster.

When a search has answered your question

When you find a post that matches your problem, a few small actions help the next person. Upvote the question and the answer that helped; that’s how good content rises (the site asks for 15 reputation points before you can vote, which you earn as people upvote your own posts). Read the comments under the answer too, since caveats often live there. And if your situation matches but the answer didn’t quite work, a comment saying what you tried and what happened is often better than a brand-new question that links back.

When you do need to ask

If a real search turns up nothing (which happens less often than you’d think), Stack Overflow expects a question built on the five-field structure from earlier. The site adds a few norms of its own.

The title is a one-line summary of the symptom and its context, written for someone scanning a list of search results. pandas to_datetime: "doesn't match format" error when one row has month 13 is a good title; Pandas problem is not. A pattern that works is <library or tool>: <what's happening> <under what conditions>. Save the explanation for the body.

The tags name the tools your question is about: the language (python), the library (pandas), and a version or platform if it matters (python-3.11, macos). You can use up to five. Tags are how the experts who follow a topic find your question, so missing or wrong tags are a common reason a perfectly good question sits unanswered.

The body follows the five fields: goal, expected, actual, reproduction, context. Stack Overflow specifically expects an MRE; its guide to writing one is in Further reading, and it’s worth rereading before you post. Format code and error output as code blocks, either with the code button or by putting three backticks on the lines before and after (the site’s formatting help shows both). Never post screenshots of code or errors: the site’s own guide to asking says in capital letters not to, because nobody can copy, run, or search the text in an image.

Edits and follow-ups keep the question useful. If someone asks for clarification in a comment, edit the question to add it, rather than replying in the comments where it will get buried. If an answer solves your problem, accept it by clicking the check mark; that’s how the site tells future searchers the question is solved. And if you figure it out yourself, post your solution as an answer to your own question. The site explicitly encourages self-answers, and yours turns a frustrating afternoon into a resource for the next person who hits the same wall.

What gets a question closed

Having a question closed stings, especially when it’s your first. It helps to know that closing is usually about the question’s format, not about you, and that the common reasons are predictable. Stack Overflow’s help page on closed questions lists them. “Needs details or clarity” means readers can’t tell exactly what’s going wrong, often because there’s no runnable example or no clear expected-versus-actual: add them. “Needs more focus” means you asked several questions in one post: split them. “Opinion-based” means you asked which tool is “best”; the site wants questions whose answers can be checked, not preferences. “Duplicate” means an existing question already covers yours, which is exactly why searching first matters. There are also site-specific reasons, like a question that isn’t really about programming.

A closed question stays online but can’t receive new answers. The good news is that closing isn’t final: you can edit a closed question to fix the problem, and an edited question can be reopened.

Stack Overflow is a tool, not a teacher

One last thing. Stack Overflow is excellent for diagnosing a specific bug, but it’s no substitute for reading the documentation or building your own understanding. If you notice you’re searching about the same tool over and over, the better move is usually to spend an hour with its official docs (see Chapter 5) instead of bookmarking another half-dozen answers. The site works best when you arrive with a focused question the docs haven’t answered.

2.8 Common traps and how to avoid them

Some mistakes are so common that they have names. Here are the ones that trip up newcomers most.

The XY problem

The XY problem happens when you ask about your attempted solution (Y) instead of your actual goal (X). The classic version: you ask “how do I pull the year out of this date string with a regex?” when what you really want is “how do I get the year from this date column?” Regex is the wrong tool for that, because pandas already has pd.to_datetime and .dt.year. But your helper only sees the regex question, so they write you an elaborate regex when one line of pandas would have done.

It’s an easy trap to fall into, because by the time you ask, you’ve been staring at Y for an hour and it feels like the problem. The fix is mechanical. Say your real goal first, in one sentence, before describing what you tried. Mention your approach as one option you considered, not the only path. And invite alternatives: even “I’m open to other approaches” goes a long way.

Copying errors by hand

Don’t retype error messages. Copy and paste them as text. Retyping introduces typos, drops details you didn’t know mattered, and makes the message harder to search for.

Screenshot-only questions

Screenshots have their place. They’re good for showing the layout of an editor, a settings dialog, or an error in a window you can’t copy text out of. But for anything a helper might want to search, copy, or paste back to you, a screenshot actively gets in the way: they’d have to retype it, and they can’t search for it. Stack traces, commands, and code should always go in as text. Attach a screenshot as well if it adds something, but put the text alongside it.

Sharing entire notebooks

A 200-cell notebook is one of the hardest things for anyone but you to debug. If you’re tempted to share a whole notebook, do three things first: point to the specific cell that fails, try to reproduce the failure in a short script outside the notebook, and clear the outputs that don’t matter, both because they bloat the file and because they sometimes contain things you didn’t realize were sensitive (Chapter 16 shows how). More often than not, getting the notebook ready to share reveals the bug before you ever send it.

2.9 Using AI tools when asking questions

AI assistants can help you shape a question, and they can also hand you a confident answer that’s wrong. The rule of thumb is to use AI to improve the structure and clarity of your question, not to skip checking the answer. Chapter 35 covers how to work with AI tools carefully, including how to verify what they tell you.

Good uses of AI when forming a question

The most reliable use is structural. Paste in your messy first description (with anything private removed) and ask the assistant to reorganize it into the five fields plus “what I tried.” It’s good at filling in the template and at pointing out fields you forgot, which is exactly what you want. It can also suggest which environment details matter for a given kind of error, propose cuts that shrink your code toward an MRE, and turn a noisy error message into a clean search query by stripping out the parts specific to your machine.

Bad uses of AI when forming a question

The worst uses come from handing over the parts of the work that need to be yours. Asking it to “fix” an error you haven’t reproduced is one: you’ll get a plausible-looking fix that may or may not touch the real cause, and you won’t learn anything you can use on the next bug. Pasting secrets, tokens, or private data into a prompt is another, and treat that as a hard rule: once a secret leaves your machine, assume it’s no longer secret (see Chapter 34). The most dangerous is running an AI-suggested command you don’t understand, especially anything with sudo, a recursive delete, or network settings.

A safe workflow

First, reproduce the error yourself, so you know exactly what you’re asking about. Then draft the question using the five fields. Next, ask the AI to improve it: clearer wording, missing context, a tighter MRE. Check any command it proposes against the official documentation before you run it. Finally, post the question, knowing that everything in it is something you’ve seen with your own eyes.

2.10 Closing the loop: after you get help

Getting the answer feels like the end, but a few more minutes turn one person’s help into something that keeps paying off, for you and for the people after you.

Summarize the solution

In the class forum, issue, or chat thread where you asked, write a short note: what the root cause was, what fixed it, and what you learned (a principle about paths, say, or environments). The next student who searches for that error will find your question and its answer, instead of a thread that ends with “nvm, fixed it.”

Update your documentation

If the fix revealed a fragile step (“always activate the environment first”), write it into your README or project notes, so future you doesn’t repeat the mistake. Chapter 3 has more on keeping notes that help.

Turn recurring problems into checklists

If you keep running into the same kind of error, make a personal checklist for it: a “file not found” checklist, an “import error” checklist, a “Git conflict” checklist. The third time you hit a problem, you’ll solve it in two minutes instead of two hours.

2.11 Stakes and politics

In April 2018, Stack Overflow’s own blog ran a post by Jay Hanlon titled Stack Overflow Isn’t Very Welcoming. It’s Time for That to Change. It admitted that “too many people experience Stack Overflow as a hostile or elitist place, especially newer coders, women, people of color, and others in marginalized groups.” The post didn’t blame a few bad actors. It blamed the company itself, which had “trained users to tell other users what they’re doing wrong” but hadn’t given new folks “the necessary guidance to do it right.”

The five-field template in this chapter is that missing guidance, and it’s also a gate. It assumes the burden of investigation falls on the asker, and that effort only counts when it’s shown in one particular idiom. People who already speak “minimal reproducible example, exact error text, environment versions” get fast answers; people still learning what those words mean get told to come back later. So help flows most easily to those who already sound like insiders. And the gold-standard MRE quietly assumes a stable laptop, a working environment, and unbroken time to iterate. A student debugging on a borrowed Chromebook between shifts has done real investigation that’s much harder to package this way. Meanwhile, paid tutoring, a well-staffed TA queue, or a senior colleague on Slack let some people skip the public-forum gauntlet entirely, and access to those is unevenly spread.

See Chapter 8 for the broader framework. The concrete prompt to carry forward: before closing, downvoting, or dismissing a “low-effort” question, ask whether the asker had access to the resources the template silently assumes.

2.12 Worked examples

Each example below starts from the kind of question everyone writes at first and turns it into one a helper can answer in a single reply. Watch how often the rewrite contains the seed of its own answer.

From “Jupyter shows no notebooks” to a working-directory diagnosis

The first draft: “Jupyter opens but my notebook files aren’t there.”

The rewrite:

Goal: Open notebooks/analysis.ipynb in JupyterLab.

Expected: JupyterLab’s file browser shows my project folder, including notebooks/analysis.ipynb.

Actual: JupyterLab opens in the browser, but the file browser shows an old folder from last semester, not my project. The terminal says Serving notebooks from local directory: /Users/alex/old-course.

Reproduction:

cd ~/Desktop/project
jupyter lab

Context: macOS 14.3, conda environment ds101, JupyterLab 4.1. I can see notebooks/analysis.ipynb in Finder.

What I tried: restarted JupyterLab; confirmed I had cd’d into the project first; ran jupyter lab --notebook-dir=. and that worked.

The rewrite nearly answers itself. Jupyter normally shows the folder you started it from, so something is telling it to start somewhere else, and the terminal line says exactly where. The usual culprit is a leftover setting (root_dir) in a jupyter_server_config.py file from an earlier setup; jupyter --paths lists the folders where Jupyter looks for those files. A folder given on the command line, like --notebook-dir=., overrides the config file, which is why that worked. Even if you didn’t know any of that, a helper can now explain it in one reply. (Chapter 16 covers how Jupyter finds your files.)

From “Git push rejected” to a fetch-and-merge plan

The first draft: “Git won’t let me push.”

The rewrite:

Goal: Push my commits on branch feature-cleaning to GitHub.

Expected: git push updates the branch on GitHub.

Actual: the push is rejected:

$ git push
To https://github.com/our-team/project.git
 ! [rejected]        feature-cleaning -> feature-cleaning (fetch first)
error: failed to push some refs to 'https://github.com/our-team/project.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.

Context: I’m working with one teammate, and we both push to the same branch.

What I tried: git pull stopped with fatal: Need to specify how to reconcile divergent branches. Then git pull --no-rebase gave CONFLICT (content): Merge conflict in cleaning.py.

Now a helper can walk you straight through it. Your teammate pushed commits you don’t have yet, so Git won’t let you overwrite them. The “divergent branches” message is Git asking you to choose how to combine the two histories, and --no-rebase chose a merge. The conflict in cleaning.py means you both edited the same lines. Open the file, resolve the conflict, commit, and push again. Chapter 31 explains each of these steps.

From “my CSV loads wrong” to a tab-delimited fix

The first draft: “My CSV loads wrong.”

The rewrite, with an MRE:

Goal: Load a tab-separated file into pandas.

Expected: three columns, name, age, and city.

Actual: pandas makes a single column holding the whole line as one string.

Reproduction:

import pandas as pd
from io import StringIO

raw = "name\tage\tcity\nAda\t35\tLondon\n"
df = pd.read_csv(StringIO(raw))
print(df.columns)

Output:

Index(['name\tage\tcity'], dtype='str')

Context: pandas 3.0.

What I tried: passing sep="\t" gives the three columns I expected.

This is a model question, even though it answers itself. The made-up data shows the whole problem in five lines, and building the MRE is what exposed the cause: read_csv assumes commas unless you tell it otherwise, and this file is tab-separated. If you get this far on your own, post it anyway, as a question with your own answer, and the next person with a mystery one-column DataFrame will find it.

2.13 Templates

Template A: question skeleton (copy and paste)

Goal:
Expected:
Actual:
Reproduction steps (exact commands / minimal code):

Context (OS, versions, environment):

What I tried (and what happened):

What I think is happening (optional hypothesis):

Template B: minimal environment report

OS:
Python:
Environment (conda/venv):
Key packages + versions:
Working directory:

Template C: MRE checklist

  • Uses the smallest amount of code that still fails.

  • Uses public or made-up data (no secrets).

  • Includes the exact error or output text.

  • Includes all necessary imports.

  • Uses explicit file paths or includes the file contents.

2.14 Exercises

  1. Take three vague questions (from your own experience or from your instructor) and rewrite them using the five-field structure.

  2. Build an MRE for a bug you ran into this week. Shrink it until it’s fewer than 20 lines.

  3. Run the 10-minute triage loop on a new error, and write down each step you took and what it showed.

  4. Post a structured question to your course forum, then update it with a summary of the solution once you get help.

  5. Swap questions with a classmate: can they reproduce your MRE without asking you anything?

2.15 One-page checklist

  • My goal is stated as a verb plus an object.

  • I clearly separate what I expected from what actually happened.

  • I include the smallest steps that reproduce the problem.

  • I include the exact error or output, as text.

  • I include the relevant environment context (OS, versions, environment).

  • I describe what I tried and what happened.

  • I chose the right channel and followed its norms.

  • I closed the loop with a summary and a documentation update.

Note📚 Further reading
  • Stack Overflow, How do I ask a good question? — the site’s own guide; short, opinionated, and worth rereading every year.
  • Stack Overflow, How to create a Minimal, Reproducible Example — the companion page on MREs, and the standard most answerers will hold your question to.
  • Eric S. Raymond, How To Ask Questions The Smart Way — the classic essay; the tone is dated and at times unwelcoming, but the structural advice holds up.
  • Julia Evans, How to ask good questions — a kinder, more inclusive complement to Raymond, full of small concrete moves that work for newcomers.
  • Jon Skeet, Writing the perfect question — practical advice from one of Stack Overflow’s highest-reputation users; especially good on titles and tags.
  • The Recurse Center, Social rules — a short, explicit set of norms (“no feigning surprise,” “no well-actually’s”) that make it easier for everyone to ask and answer technical questions.