Learning objectives
After reading this article you will be able to:
- Tell normal output (stdout) from errors (stderr) and find the first error line
- Read a Node.js stack trace and a Python traceback
- Write useful logs and recognize the most common startup errors
When an app stops responding, the log is the first place to look. It is the process's diary: everything your code prints and everything the runtime complains about ends up there. Knowing how to read it saves hours of guessing.
The problem is rarely missing information; it's too much of it. A production log has hundreds of lines, and the useful error is one of them. To reach it, follow a fixed method in the same order every time.
Where do log lines come from?#
Every process has two output streams. stdout carries normal output: console.log in Node.js, print in Python. stderr carries errors: console.error and the message the runtime prints when an exception is not handled.
In a terminal or a hosting dashboard, the two appear interleaved, in the order they arrived. That helps, because you see what the app was doing right before it failed.
In Node.js, an uncaught exception prints the stack trace to stderr and exits with code 1, according to the process documentation. An unhandled promise rejection (unhandledRejection) is, by default, raised as an uncaught exception. That is why an await without try/catch can take down your whole bot.
What is the method for finding the error?#
Here are the steps:
- Go to the end of the log. The last thing that happened is the current symptom.
- Scroll up to the first error line. Look for
Error,Exception,Traceback,FATALorECONNREFUSED. Warnings (warn) are rarely the cause. - Read the whole message. It gives the error type and, almost always, what was missing: a module, a variable, a port.
- Find the first line of your own code in the stack trace. Lines from
node_modulesor libraries show where the error passed through. The line with your file path shows where your code triggered it. - Check what happened before. A database connection failure may have started 30 lines above the final error.
If the app restarts several times in a row, the log keeps each attempt, one after another. Compare the last one with the one before: the error that repeats is the one that matters.
How do you read a Node.js stack trace?#
Here is an example of an unhandled exception:
/home/app/index.js:12
const name = user.profile.name;
^
TypeError: Cannot read properties of undefined (reading 'name')
at getName (/home/app/index.js:12:29)
at handleMessage (/home/app/handlers/message.js:8:5)
Node.js v24.0.0Read it top to bottom:
- The line with
^points at the exact spot in the code. TypeError: ...is the type and message. Here,user.profileisundefined.- The
atlines are the call stack, newest first. The first line with your project path (/home/app/index.js:12:29) gives file, line and column. - The last line shows the Node.js version, handy to confirm the runtime in use.
A Node stack trace shows where the error was created and extends to the start of synchronous execution, or to the frame limit set by Error.stackTraceLimit (see the errors documentation). In async code, some intermediate calls may not appear.
How do you read a Python traceback?#
Python uses the opposite order: the most recent call comes last.
Traceback (most recent call last):
File "/home/app/main.py", line 20, in <module>
start()
File "/home/app/main.py", line 14, in start
token = os.environ["TOKEN"]
File "<frozen os>", line 714, in __getitem__
KeyError: 'TOKEN'Start with the last line: KeyError: 'TOKEN' says the TOKEN environment variable does not exist. Then go up to find the line of your code that caused it (main.py, line 14). The header Traceback (most recent call last) tells you the newest call is at the bottom, as shown in the traceback module documentation.
When two exceptions are chained, Python prints During handling of the above exception, another exception occurred: between the blocks. The original cause is in the first block, and the error that finally propagated is in the last.
Which errors show up most when starting an app?#
| Log message | Likely cause | What to do |
|---|---|---|
Cannot find module 'x' / ModuleNotFoundError |
Dependency not installed or missing from package.json / requirements.txt |
Add the dependency and deploy again |
KeyError or undefined on an environment variable |
Variable not set | Set it and restart. See environment variables |
EADDRINUSE |
Port already used by another process | Use the right port or stop the other process |
ECONNREFUSED |
Database or service down, wrong host or port | Check host, port and that the service is up |
JavaScript heap out of memory / MemoryError |
Not enough RAM | Raise the RAM or reduce usage. See how much RAM and CPU |
Invalid token / 401 |
Wrong or expired credential | Generate a new one and update the variable |
If the app crashes and comes back in a loop, the log shows the same error at every start. That is a restart loop caused by a fixed error, and automatic restart only repeats it. Read the guide on PM2 and auto-restart to understand this behavior.
How do you write logs that actually help?#
A good log answers "what, when and with which data" without exposing secrets.
- Use levels.
infofor normal milestones,warnfor what deserves attention,errorfor failures. That lets you filter. - Include context.
failed to save user 4821: timeoutbeatserror. - Log the whole error object, not just the message. Without the stack trace you lose the location of the failure.
- Never print passwords, tokens or personal data. More people read a log than you think.
- Write to stdout and stderr. That way you don't depend on a file path or rotation.
A minimal Node.js example:
process.on("unhandledRejection", (reason) => {
console.error("unhandledRejection:", reason);
});
async function save(id) {
try {
await db.save(id);
console.log(`user ${id} saved`);
} catch (error) {
console.error(`failed to save user ${id}`, error);
}
}In Python, the standard library's logging module does the same, and logging.exception("message") already includes the traceback.
How to do this on Square Cloud#
On Square Cloud, your app's logs appear in real time in the dashboard, the CLI, the VS Code extension and the mobile app. You apply the same method and follow a deploy or an error without opening a terminal on any server.
Apps run in isolated containers. Automatic restart is optional and comes on when you deploy from the dashboard: it brings the app back when the process exits with an error. Logs from before a restart stay visible, so after an unexpected restart, scroll up the log to find the error that caused it. Running out of memory is different: the app stops and only comes back when you raise its RAM and start it again.
When you change an environment variable, the change takes effect on the next restart, with no rebuild: restart and reread the log to confirm. Cubic, the AI agent in the dashboard, also reads logs to diagnose failures, always at your request. CPU, RAM and network metrics are recorded every 5 minutes and kept for 24 hours, which helps you match a memory error with real usage.
See the logs and metrics features in the platform features.
Deploy
Push from GitHub, the CLI or a ZIP and go live in seconds
FAQs
Why does the log show an error while the app keeps running?
Not every error stops the process. An error caught by try/catch and only printed does not end the app. An uncaught exception does end the process, and an automatic restart can bring it back, so it looks like it never went down.
What is the difference between stdout and stderr?
They are two output streams of a process. console.log and print write to stdout. console.error and uncaught exception messages go to stderr. In a dashboard the two usually appear together, in the order they arrive.
The log shows only one line of the error. Where is the rest?
Check whether the dashboard limits the visible lines and scroll up. An exception spans several lines, and the real cause may be on the first line of the stack trace or in a chained block, such as 'During handling of the above exception' in Python.
Can I write logs to a file?
You can, but it is usually better to write to stdout and stderr and let the platform collect them. If you write to a file, cap its size and rotate it, or the disk fills up.
More in Deploy
See all 33 articles- What are environment variables?Environment variables are key-value pairs the operating system hands to a process at startup. Learn to read them in Node.js and Python and keep tokens out of code.
- What is a deployment?A deployment takes a version of your code to a server, prepares it and starts it. See the stages, the methods and how to roll back when it goes wrong.
- How much RAM and CPU does my app need?Size RAM and CPU by measuring your app's real peak and adding about 30% headroom. Learn how to measure in Node.js, Python and Java and what to do if short.
- Automatic deploys with GitHub ActionsAutomatic deploys with GitHub Actions ship your code to the server on every push. See the workflow step by step, secrets, tests before deploy and common errors.