Why is `pm.response` unavailable in a Postman pre-request script, and what is missing from the test hook?
answer
- The surface differs by moment
- Nothing has replied yet
- You cannot un-send a request
- Reply in the later hook, skip in the earlier
basics
~10 sBecause no reply exists yet. pm.response is provided only in the test hook, after the send; pm.execution.skipRequest is provided only in the pre-request hook, while the send can still be abandoned.
solid answer
~40 sThe sandbox does not hand every script the same `pm.*` surface — it hands each hook the surface its moment can support. A pre-request script runs before anything is sent, so there is no reply for `pm.response` to hold and it is simply not there. A test script runs after the reply has arrived, so the send is already finished and `pm.execution.skipRequest` has nothing left to abandon; it is not there either. Neither absence is a restriction someone chose to impose for safety — each is what the moment physically allows. The useful consequence is diagnostic: **which members resolve tells you which hook you are in**, so probing for `pm.response` is a quick way to confirm that a script you thought ran before the send actually runs after it.
go deeper
Recall which hook sees the reply and which can call off a send. Say plainly why: before the send nothing has answered, and after the reply nothing can be un-sent.
Explain that the sandbox exposes a different surface per moment and that the two hooks are separate executions rather than one paused script, so no object is shared across the send.
Use the asymmetry as a diagnostic: probe which members resolve to confirm the moment before debugging code, since a misplaced script fails silently and shows its symptom far from its cause.
Set the expectation that scripts are written for a moment, not for a request. Review conventions should make the hook obvious at a glance so silent no-ops never reach a shared collection.
## The surface follows the moment Scripts in this tool run in a **sandbox** — an isolated JavaScript context — and everything they can touch arrives through the `pm` object the sandbox provides. What is easy to miss is that `pm` is **not identical in both hooks**. Each of the two moments around a send gets the surface its moment can actually support, and two members are the clean illustrations: - **`pm.response`** — the reply. Present in the **test** hook only. - **`pm.execution.skipRequest`** — the way a script says this send should not happen. Present in the **pre-request** hook only. Neither absence is a policy decision layered on for safety. Each is a consequence of when the code runs. ## Why the reply is missing before the send A pre-request script runs **before** the request has been handed to the transport. At that instant no bytes have left, no server has been contacted, and nothing has come back. There is no response object to expose, so the sandbox does not fabricate an empty one to keep the shape consistent — the member is simply absent, and code that reaches for it finds nothing. The common wrong mental model is that `pm.response` is a slot that gets filled in as the send completes, so a pre-request script holds an empty version of the same object the test hook later reads. It does not. The pre-request execution has already ended by the time a reply exists; the two hooks are **separate executions**, not one long-running script paused around the send. ## Why the skip is missing after the reply The mirror case is easier to accept once stated: a test script runs **after** the reply has arrived. The request went out; a server answered. "Do not send this" is no longer a thing that can be said, because it has been sent. So `pm.execution.skipRequest` is exposed in the earlier hook, where abandoning is still possible, and not in the later one, where it would be meaningless. | | pre-request hook | test hook | |---|---|---| | the send has happened | no | yes | | `pm.response` | absent | present | | `pm.execution.skipRequest` | present | absent | | request edits still matter | yes | no | ## Using the surface as a diagnostic This asymmetry is more than trivia, because it gives you a way to answer "which hook am I actually in?" from **inside** the running code rather than by hunting through the file: 1. If `pm.response` resolves, the send is done. Nothing you write onto the request from here can travel. 2. If `pm.execution.skipRequest` resolves, you are still before the send, and the outgoing call is still yours to shape. 3. If neither behaves the way you assumed, the script is hanging from a different `event` entry than you thought. That check is worth reaching for early, because the failure it detects is silent. A script placed in the wrong moment does not throw; it runs, does something harmless, and produces a symptom far away from its cause. ## The mental model worth carrying Think of the send as a wall, with one execution on each side: - **Before the wall** you can still change the call — the outgoing request is the live object — and you can call the whole thing off. - **After the wall** the call is history and the reply is the live object; the request is a record of what was sent, not a lever. Everything about the two hooks follows from that: which members exist, which edits matter, and which questions each hook is even capable of answering. When someone asks why the reply is missing in a pre-request script, the answer is not a rule to memorise — it is that **there is nothing there yet**, and the surface is honest about it. ## Anti-patterns this rules out - Writing one script that inspects the reply and then adjusts the outgoing request. That needs both sides of the wall in one execution, which does not exist. - Guarding pre-request code with a check on the reply to "handle both cases" — the guard is always false in the earlier hook, so the code is dead. - Calling the skip after seeing a bad reply, expecting the call to be retracted. The bytes are already out; the only thing that hook can influence is what happens next, not what already happened.
- How can a running script tell which of the two hooks it is executing in?Probe the surface. If `pm.response` resolves, the send has already happened and no request edit from there can travel; if `pm.execution.skipRequest` resolves, the code is still before the send. That check answers the question from inside the execution, which is faster than tracing which `event` entry the script actually hangs from.
- Is a pre-request script given an empty response object it can fill in later?No. The two hooks are separate executions, not one script paused around the send, so there is no shared object to fill in. The pre-request execution has ended before any reply exists, and the reply is exposed freshly to the later execution. Values that must travel between them go through a variable scope.
saying these in an interview costs you the question
- Thinks the reply object exists but is empty pre-send
- Treats the two hooks as one paused execution
- Expects to abandon a send after seeing the reply
- Assumes both hooks receive an identical pm surface
- Guards pre-send code with a check on the reply