Stack Traces
Understand stack trace capture, source maps, and symbolication for better debugging.
Overview
Stack traces are essential for debugging errors. They show the exact code path that led to an error, including file names, function names, and line numbers.
Stack Trace Structure
Each stack trace consists of frames - individual function calls in the call stack:
interface StackFrame {
filename: string; // File path
function: string; // Function name
lineno: number; // Line number
colno?: number; // Column number
contextLine?: string; // The actual code line
preContext?: string[]; // Lines before
postContext?: string[]; // Lines after
inApp?: boolean; // Is this your code?
module?: string; // Module/package name
}Example Stack Trace
{
"frames": [
{
"filename": "src/components/UserCard.tsx",
"function": "UserCard",
"lineno": 42,
"colno": 15,
"contextLine": "const name = user.profile.name;",
"preContext": [
"export function UserCard({ user }: Props) {",
" const [loading, setLoading] = useState(false);"
],
"postContext": [
" const email = user.profile.email;",
" return ("
],
"inApp": true
},
{
"filename": "node_modules/react-dom/cjs/react-dom.development.js",
"function": "renderWithHooks",
"lineno": 14985,
"colno": 18,
"inApp": false,
"module": "react-dom"
}
]
}In-App vs Library Frames
The SDK distinguishes between your code and library code:
- In-App Frames (
inApp: true) - Your application code - Library Frames (
inApp: false) - Code from node_modules, runtime, etc.
Configuring In-App Detection
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
// Patterns for in-app code
inAppInclude: [
'src/',
'app/',
'components/',
],
// Patterns for library code
inAppExclude: [
'node_modules/',
'webpack/',
'__next/',
],
});Source Maps
Production code is typically minified, making stack traces unreadable:
// Minified stack trace (unhelpful)
Error: Cannot read property 'name' of undefined
at a.render (main.js:1:4523)
at e.update (main.js:1:8934)
Source maps translate minified code back to original source:
// With source maps (helpful!)
Error: Cannot read property 'name' of undefined
at UserCard (src/components/UserCard.tsx:42:15)
at Dashboard.render (src/pages/Dashboard.tsx:88:20)
Uploading Source Maps
During Build
// vite.config.ts
import { observabilityPlugin } from '@transactional/observability/vite';
export default {
plugins: [
observabilityPlugin({
authToken: process.env.OBSERVABILITY_AUTH_TOKEN,
org: 'your-org',
project: 'your-project',
release: process.env.APP_VERSION,
}),
],
build: {
sourcemap: true, // Generate source maps
},
};Webpack
// webpack.config.js
const { ObservabilitySourceMapPlugin } = require('@transactional/observability/webpack');
module.exports = {
devtool: 'source-map',
plugins: [
new ObservabilitySourceMapPlugin({
authToken: process.env.OBSERVABILITY_AUTH_TOKEN,
org: 'your-org',
project: 'your-project',
release: process.env.APP_VERSION,
}),
],
};CLI Upload
# Upload source maps manually
npx @transactional/observability sourcemaps upload \
--auth-token $OBSERVABILITY_AUTH_TOKEN \
--org your-org \
--project your-project \
--release 1.2.3 \
./distRelease Matching
Source maps are associated with a release. The release in your SDK config must match:
// SDK config
initObservability({
dsn: 'your-dsn',
release: '1.2.3', // Must match upload
});# Upload command
npx @transactional/observability sourcemaps upload --release 1.2.3 ./distNext.js Source Maps
// next.config.js
const { withObservability } = require('@transactional/observability/nextjs');
module.exports = withObservability({
authToken: process.env.OBSERVABILITY_AUTH_TOKEN,
org: 'your-org',
project: 'your-project',
})({
// Your Next.js config
productionBrowserSourceMaps: true,
});Context Lines
Context lines show the actual code around the error:
// Error occurred here:
// Line 40: const [loading, setLoading] = useState(false);
// Line 41:
// Line 42: const name = user.profile.name; // <-- Error line
// Line 43: const email = user.profile.email;
// Line 44:Configuring Context Lines
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
stackTrace: {
// Number of lines before the error line
preContextLines: 3,
// Number of lines after the error line
postContextLines: 3,
},
});Node.js Stack Traces
Async Stack Traces
Node.js 12+ supports async stack traces:
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
platform: 'node',
stackTrace: {
// Enable async stack traces (more context, more overhead)
asyncStackTraces: true,
},
});V8 Stack Trace Limit
Increase the default stack trace limit:
// At the top of your entry file
Error.stackTraceLimit = 50; // Default is 10
initObservability({
dsn: 'your-dsn',
// ...
});Browser Stack Traces
Cross-Origin Scripts
Errors from cross-origin scripts show limited information:
Script error.
at <anonymous>:0:0
Fix with CORS headers:
<!-- Add crossorigin attribute -->
<script src="https://cdn.example.com/app.js" crossorigin="anonymous"></script>Access-Control-Allow-Origin: *
Dynamically Generated Code
Stack traces from dynamically generated code strings have limited context. For better error tracking, prefer static code patterns where possible.
Python Stack Traces
Symbolication
Python stack traces include full file paths:
Traceback (most recent call last):
File "/app/services/user_service.py", line 42, in get_user
return db.query(User).filter(User.id == user_id).one()
File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/query.py", line 2789, in one
raise exc.NoResultFound("No row was found for one()")
sqlalchemy.orm.exc.NoResultFound: No row was found for one()Frame Filtering
from transactional_observability import init_observability
init_observability(
dsn="your-dsn",
enable_error_tracking=True,
# Include patterns for in-app code
in_app_include=[
"app",
"services",
"api",
],
# Exclude patterns
in_app_exclude=[
"site-packages",
"venv",
],
)Stack Trace Limits
To avoid excessive data, stack traces are limited:
| Setting | Default | Max |
|---|---|---|
| Max frames | 100 | 250 |
| Context lines (pre) | 3 | 10 |
| Context lines (post) | 3 | 10 |
| Max frame filename length | 256 | 512 |
Configuring Limits
initObservability({
dsn: 'your-dsn',
enableErrorTracking: true,
stackTrace: {
maxFrames: 150,
preContextLines: 5,
postContextLines: 5,
maxFilenameLength: 300,
},
});Viewing Stack Traces
In the Dashboard
- Go to Issues in your project
- Click an issue to view details
- Stack traces are shown with:
- In-app frames highlighted
- Expandable library frames
- Clickable file/line links
- Context lines when available
Frame Grouping
The dashboard groups frames by:
- In-App - Your application code (expanded by default)
- Framework - React, Next.js, etc.
- Library - node_modules packages
- System - Runtime and native code
Troubleshooting
Missing Source Maps
- Check upload - Verify source maps were uploaded for the release
- Check release - Ensure SDK
releasematches upload--release - Check paths - Source map paths must match deployed file paths
Minified Stack Traces
If you see minified code:
- Enable source map generation in your bundler
- Upload source maps with matching release
- Check that production builds include source map references
Missing Context Lines
Context lines require:
- Source maps with embedded sources, OR
- Source map upload with original files
// vite.config.ts
export default {
build: {
sourcemap: true,
rollupOptions: {
output: {
sourcemapExcludeSources: false, // Include sources in map
},
},
},
};Best Practices
1. Always Generate Source Maps
// vite.config.ts
export default {
build: {
sourcemap: true,
},
};2. Upload on Every Deploy
# CI/CD pipeline
- name: Build
run: npm run build
- name: Upload Source Maps
run: |
npx @transactional/observability sourcemaps upload \
--release ${{ github.sha }} \
./dist3. Use Semantic Releases
initObservability({
dsn: 'your-dsn',
release: `${process.env.APP_NAME}@${process.env.APP_VERSION}`,
});4. Clean Up Old Source Maps
# Delete source maps older than 90 days
npx @transactional/observability sourcemaps delete \
--older-than 90d \
--org your-org \
--project your-projectNext Steps
- Breadcrumbs - Track user actions
- Context - Add debugging context
- Alerts - Configure error notifications
On This Page
- Overview
- Stack Trace Structure
- Example Stack Trace
- In-App vs Library Frames
- Configuring In-App Detection
- Source Maps
- Uploading Source Maps
- During Build
- Webpack
- CLI Upload
- Release Matching
- Next.js Source Maps
- Context Lines
- Configuring Context Lines
- Node.js Stack Traces
- Async Stack Traces
- V8 Stack Trace Limit
- Browser Stack Traces
- Cross-Origin Scripts
- Dynamically Generated Code
- Python Stack Traces
- Symbolication
- Frame Filtering
- Stack Trace Limits
- Configuring Limits
- Viewing Stack Traces
- In the Dashboard
- Frame Grouping
- Troubleshooting
- Missing Source Maps
- Minified Stack Traces
- Missing Context Lines
- Best Practices
- 1. Always Generate Source Maps
- 2. Upload on Every Deploy
- 3. Use Semantic Releases
- 4. Clean Up Old Source Maps
- Next Steps