Error Tracking
Detect, deduplicate, and track Python errors in your Odoo instances with optional GitHub Issue creation.
oCore automatically detects Python tracebacks and common error patterns in your Odoo instance logs, groups them by fingerprint, tracks occurrences over time, and optionally creates GitHub Issues when errors cross a threshold. This gives you a centralized view of production errors without installing any Odoo module or third-party APM tool.
Error Tracker
View detected errors, occurrence trends, and linked GitHub Issues.
How It Works
Error tracking follows a pipeline that runs automatically whenever oCore collects logs from a running instance:
- Log collection -- oCore reads container logs from your Odoo instances via SSH
- Error detection -- Log lines are scanned for Python tracebacks (
Traceback (most recent call last):) and non-traceback patterns (database errors, access errors, module warnings) - Fingerprinting -- Each detected error is hashed using SHA-256 over the exception type, custom addon stack frames (excluding line numbers), and module name. This produces a stable identifier even when the same error occurs on different lines
- Deduplication -- The fingerprint is matched against existing records. If a match is found, the occurrence count is incremented. If not, a new error record is created
- Occurrence tracking -- Each occurrence is recorded in hourly histogram buckets, enabling sparkline charts and timeline views
- GitHub Issue creation -- When configured and the occurrence threshold is met, oCore creates a GitHub Issue with a Copilot-optimized body containing the traceback, affected files, and context lines
Severity Classification
Errors are classified automatically based on the detection type:
| Severity | Criteria |
|---|---|
| Critical | Full Python tracebacks with stack frames |
| High | Database errors (deadlocks, connection refused, unique constraint violations) and access errors (AccessError, PermissionError) |
| Medium | Odoo module warnings and other non-traceback error log lines |
Error Lifecycle
Each error fingerprint moves through a status lifecycle:
new -> active -> resolved -> regressed -> active -> ...| Status | Meaning |
|---|---|
| New | First occurrence detected, not yet seen again |
| Active | Seen more than once, actively occurring |
| Resolved | No occurrences for 3 days (auto-resolved) |
| Regressed | Was resolved but reappeared |
Enabling Error Detection
Error detection is controlled per instance. By default, the setting is inherited from the environment type:
- Production environments -- error detection is ON by default
- Development and staging environments -- error detection is OFF by default
Toggling Error Detection
You can override the default for any instance:
# Enable error detection
curl -X PUT https://ocore.example.com/api/instances/{instanceId} \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"errorDetectionEnabled": true}'
# Disable error detection
curl -X PUT https://ocore.example.com/api/instances/{instanceId} \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"errorDetectionEnabled": false}'You can also toggle this from the instance settings page in the dashboard.
No Odoo Module Required
Error detection works by analyzing container logs over SSH. There is nothing to install in your Odoo instance -- no Python package, no Odoo module, no configuration change.
Error Dashboard
The error dashboard shows all detected errors across your organization, with filtering and sorting options.
Error Dashboard
View and filter all detected errors across your instances.
Summary Stats
The top of the dashboard shows four key metrics:
| Metric | Description |
|---|---|
| Total Active | Errors with status new, active, or regressed (excluding muted) |
| New (24h) | Errors first detected in the last 24 hours |
| Critical | Active errors with critical severity |
| Issues This Week | GitHub Issues created from errors in the last 7 days |
Filtering
Filter the error list using any combination of:
| Filter | Options |
|---|---|
| Severity | critical, high, medium |
| Status | new, active, resolved, regressed |
| Module | Substring match on the Odoo module name (e.g., sale, stock) |
| Instance | Show only errors affecting a specific instance |
| Date range | Filter by since and until timestamps |
| Show muted | Include muted errors in the results (hidden by default) |
Sorting
Sort errors by:
- Last seen (default) -- most recently occurring errors first
- Total count -- most frequent errors first
- Severity -- critical first, then high, then medium
Sparkline Charts
Each error in the list includes a 7-day sparkline chart showing hourly occurrence counts. This gives you a quick visual of whether an error is trending up, stable, or fading.
Error Detail
Click any error to open the detail view, which includes:
Traceback
The full Python traceback as captured from the log output. For chained exceptions, the entire chain is preserved.
Stack Frames
Parsed stack frames showing:
- File path -- The Python file where the error occurred
- Line number -- The line in the source file
- Function name -- The function or method containing the error
oCore identifies the Odoo module from the file path by checking known addon directories (/mnt/extra-addons/, /mnt/custom-addons/, etc.).
Context Lines
Up to 10 log lines before the traceback and 3 lines after are captured to provide surrounding context for debugging.
Occurrence Timeline
An hourly histogram of occurrences over the selected period (default 7 days, up to 90 days). Use this to correlate error spikes with deployments or other events.
# Fetch timeline data for the last 30 days
curl "https://ocore.example.com/api/errors/{errorId}/timeline?days=30" \
-H "Authorization: Bearer $TOKEN"Affected Instances
A list of all instances where this error has been detected, with instance names and slugs for easy identification. This helps you determine if an error is isolated to one instance or widespread.
Metadata
Additional context displayed on the detail view:
- Odoo version at the time of detection
- Commit SHA if available from the deployment
- First seen / last seen timestamps
- Resolved at timestamp (if the error was previously resolved)
- GitHub Issue link (if an issue was created)
GitHub Issues
oCore can automatically create GitHub Issues when errors are detected, using the repository connected to your project via Git Integration.
How Issue Creation Works
An error fingerprint crosses the occurrence threshold (configured per project).
oCore checks the daily issue creation cap to prevent flooding your repository.
A GitHub Issue is created with a structured body containing the exception type, severity, traceback, file paths, affected instances, and context lines.
Labels are automatically applied: bug, ocore-error, severity:{level}, and module:{name}.
The issue number is stored on the error fingerprint and linked in the dashboard.
Issue Body Format
The issue body is formatted for readability by both humans and GitHub Copilot:
- Exception type and module as the header
- Severity, first/last seen, occurrence count, and affected instances as metadata
- Full traceback in a Python code block
- File paths with line numbers and function names
- Surrounding context lines in a collapsible
<details>section - A note that sensitive data has been redacted
Automatic Labels
oCore ensures the following labels exist in your repository and applies them:
| Label | Color | Purpose |
|---|---|---|
bug | Red | Standard bug label |
ocore-error | Purple | Identifies oCore-generated issues |
severity:critical | Dark red | Critical severity |
severity:high | Light red | High severity |
severity:medium | Yellow | Medium severity |
module:{name} | Grey | The Odoo module where the error originated |
regression | Orange | Added when a resolved error reappears |
Auto-Close on Resolution
When an error has no occurrences for 3 days, oCore:
- Transitions the fingerprint status to
resolved - Closes the linked GitHub Issue
- Posts a comment: "No occurrences for 3 days. Auto-resolved by oCore."
Auto-Reopen on Regression
If a resolved error reappears:
- The fingerprint status transitions to
regressed - The linked GitHub Issue is reopened
- The
regressionlabel is added - A comment is posted with the new occurrence timestamp and affected instance
Sensitive Data Redaction
Before writing tracebacks to GitHub Issues, oCore scrubs sensitive data including:
- Connection strings (
://user:password@host) - DSN password values
- AWS access keys (
AKIA...) - GCP API keys (
AIza...) - Environment variables containing
secret,token,key,password, orcredential
Redaction Is Best-Effort
Automatic redaction covers common patterns but cannot catch every possible secret format. Review your tracebacks before sharing issue links externally.
Authentication
oCore authenticates with GitHub using either:
- GitHub App -- Preferred. Uses the organization's GitHub App installation (see Git Integration)
- Personal Access Token -- Falls back to the encrypted PAT stored on the Git repository configuration
Muting Errors
Muting an error hides it from the default dashboard view and prevents GitHub Issue creation for that fingerprint. The error continues to be tracked (occurrences are still recorded), but it will not appear unless you enable the Show muted filter.
When to Mute
- Known harmless errors you cannot fix (e.g., third-party module bugs)
- Expected errors during migrations or maintenance windows
- Noisy low-severity warnings that clutter the dashboard
Mute / Unmute
# Mute an error
curl -X POST https://ocore.example.com/api/errors/{errorId}/mute \
-H "Authorization: Bearer $TOKEN"
# Unmute an error
curl -X POST https://ocore.example.com/api/errors/{errorId}/unmute \
-H "Authorization: Bearer $TOKEN"You can also mute and unmute from the error detail view in the dashboard.
Custom Ignore Patterns
Each instance can define custom ignore patterns to skip known harmless log messages before they enter the error tracking pipeline. Patterns are matched using simple substring matching (strings.Contains).
Setting Ignore Patterns
curl -X PUT https://ocore.example.com/api/instances/{instanceId} \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"errorIgnorePatterns": [
"l10n_mx.tax.rate: Tax rate mismatch",
"mail.thread: Failed to send notification"
]
}'Default Ignore Patterns
oCore ships with built-in ignore patterns that are always active:
odoo.modules.loading: Modules loadedodoo.service.server: HTTP serviceDeprecationWarning:PendingDeprecationWarning:ResourceWarning: unclosedUserWarning: Fieldsodoo.tools.translate: unable to find translation
Custom patterns are checked in addition to the defaults. You do not need to repeat the defaults in your custom list.
Merging Errors
If the fingerprinting algorithm creates separate records for what is logically the same error, you can merge them. Merging combines occurrence counts into a primary error and hides the secondary errors.
curl -X POST https://ocore.example.com/api/errors/merge \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"primaryId": "PRIMARY_ERROR_UUID",
"secondaryIds": ["SECONDARY_1_UUID", "SECONDARY_2_UUID"]
}'Up to 50 errors can be merged in a single request. Merged errors are hidden from the list view.
Error Fingerprinting
oCore uses a deterministic fingerprinting algorithm to group related errors into a single record, even when they occur at different line numbers or across different instances.
How Fingerprinting Works
Each detected error is hashed using SHA-256 over three components:
- Exception type -- The Python exception class name (e.g.,
ValueError,AccessError) - Custom addon stack frames -- File paths and function names from your custom addon directories, excluding line numbers so that minor code changes do not create duplicate fingerprints
- Module name -- The Odoo module where the error originated, extracted from the file path
This produces a stable hash that groups occurrences of the same root cause together.
Enrichment Fields
When available, fingerprints are enriched with additional context:
| Field | Description |
|---|---|
| Cron Job Name | Name of the scheduled action that triggered the error |
| Server Action ID | ID of the Odoo server action involved |
| Odoo Model | The model being operated on when the error occurred |
| Database Name | The Odoo database name |
| HTTP URL | The request URL that triggered the error |
| ACL Operation | The access control operation (read, write, create, unlink) |
| ACL UID | The Odoo user ID that encountered the access error |
Affected Instances
Each fingerprint tracks up to 100 affected instance IDs. When the same error appears on a new instance, it is added to the affected instances list. This lets you quickly determine whether an error is isolated to one instance or widespread across your organization.
Occurrence Histogram
Occurrences are stored in hourly histogram buckets per fingerprint per instance. This enables:
- Sparkline charts on the error list showing 7-day occurrence trends
- Timeline views on error detail pages with up to 90 days of hourly data
- Spike detection to correlate error bursts with deployments or other events
Batch Histogram Loading
The error list uses batch histogram loading to fetch sparkline data for multiple fingerprints in a single query, reducing the number of database round trips.
Cooldown
To prevent re-processing the same error in rapid succession, oCore applies a 5-minute cooldown per fingerprint hash. If the same error is detected within 5 minutes of the last occurrence, the fingerprint is updated but the full detection pipeline is not re-run.
Deduplication Concurrency
When multiple background workers detect the same new error simultaneously, oCore handles the race condition gracefully. If a unique constraint violation occurs during fingerprint creation, the operation is retried as an update to the existing record.
Issue Grouping
Error fingerprints can be grouped together when the fingerprinting algorithm creates separate records for what is logically the same root cause.
Automatic Grouping
oCore automatically groups errors by:
- Status lifecycle -- New errors become active on second occurrence, auto-resolve after 3 days of inactivity, and transition to regressed if they reappear
- Severity classification -- Errors are classified as critical (full tracebacks), high (database/access errors), or medium (module warnings) based on detection type
- Module extraction -- The Odoo module is extracted from the file path to group errors by their source module
Manual Merging
When automatic grouping is not sufficient, you can manually merge fingerprints:
curl -X POST https://ocore.example.com/api/errors/merge \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"primaryId": "PRIMARY_ERROR_UUID",
"secondaryIds": ["SECONDARY_1_UUID", "SECONDARY_2_UUID"]
}'Merging:
- Combines total occurrence counts into the primary fingerprint
- Sets
merged_into_idon secondary fingerprints, hiding them from the list - Supports up to 50 secondary fingerprints per merge request
- Runs in a database transaction for consistency
Aggregate Statistics
The error dashboard provides four aggregate stats computed across all your projects:
| Stat | Description |
|---|---|
| Total Active | Errors with status new, active, or regressed (excluding muted) |
| New (24h) | Errors first detected in the last 24 hours |
| Critical | Active errors with critical severity |
| Issues This Week | GitHub Issues created from errors in the last 7 days |
Soft Delete
Fingerprints use soft deletion (via deleted_at timestamp). Soft-deleted fingerprints are excluded from all queries, including upsert lookups, ensuring that deleted errors do not resurface.
Required Permissions
| Action | Required Permission | Roles |
|---|---|---|
| View error list and details | view:errors | Owner, Admin, Developer, Viewer |
| Mute, unmute, and merge errors | manage:errors | Owner, Admin, Developer |
Troubleshooting
No errors detected for a running instance
- Verify that
error_detection_enabledis set totrue(ornullfor environment default) on the instance - Check that the instance is in a production environment (dev/staging instances have detection off by default)
- Confirm the instance is running and producing logs
- Check that your error is not matched by a default or custom ignore pattern
GitHub Issues not being created
- Verify that the project has a connected GitHub repository (see Git Integration)
- Check that a GitHub App installation or Personal Access Token is configured
- Confirm the daily issue creation cap has not been reached
- Ensure the error fingerprint is not muted
Same error appearing as multiple entries
- The fingerprinting algorithm uses exception type, custom addon stack frames, and module name. If these differ (e.g., different call paths to the same root cause), separate fingerprints are created
- Use the Merge feature to combine duplicates into a single entry
Errors reappearing after resolution
- This is expected behavior. If a resolved error occurs again, it transitions to
regressedstatus - If a GitHub Issue exists, it is reopened with a
regressionlabel - Investigate whether a recent deployment reintroduced the bug