problem-management
$
npx mdskill add serac-labs/serac/problem-managementManages ServiceNow problems with root cause analysis and known error tracking
- Creates problems from linked incidents and detects recurring patterns
- Uses ServiceNow tables like problem, incident, and known_error with Snow tools
- Applies 5-Whys analysis and KEDB searches to identify root causes
- Links permanent fixes to changes and creates knowledge articles for workarounds
SKILL.md
.github/skills/problem-managementView on GitHub ↗
---
name: problem-management
description: Manage ServiceNow problems — create from linked incidents, proactive pattern detection, RCA with 5-Whys, known_error workarounds (KEDB), KEDB search by CI/category/keywords, and permanent-fix linkage to changes.
license: Apache-2.0
compatibility: Designed for Snow-Code and ServiceNow development
metadata:
author: serac
version: "1.0.0"
category: servicenow
tools:
- snow_query_table
- snow_find_artifact
- snow_execute_script_with_output
- snow_knowledge_article_create
---
# Problem Management for ServiceNow
Problem Management identifies root causes of incidents and implements permanent solutions.
## Problem Lifecycle
```
New (1)
↓
Assess (2)
↓
Root Cause Analysis (3)
↓
Fix in Progress (4) ← Known Error Database
↓
Resolved (5)
↓
Closed (6)
Cancelled (7) ← Can occur from any state
```
## Key Tables
| Table | Purpose |
| -------------- | --------------------------- |
| `problem` | Problem records |
| `problem_task` | Problem investigation tasks |
| `known_error` | Known Error Database (KEDB) |
| `incident` | Related incidents |
## Creating Problems (ES5)
### Create Problem from Incidents
```javascript
// Create problem from multiple incidents (ES5 ONLY!)
function createProblemFromIncidents(incidentSysIds, problemData) {
// Create problem
var problem = new GlideRecord("problem")
problem.initialize()
problem.setValue("short_description", problemData.title)
problem.setValue("description", problemData.description)
problem.setValue("category", problemData.category)
problem.setValue("subcategory", problemData.subcategory)
// Set impact based on related incidents
var highestImpact = 3
for (var i = 0; i < incidentSysIds.length; i++) {
var incident = new GlideRecord("incident")
if (incident.get(incidentSysIds[i])) {
var incImpact = parseInt(incident.getValue("impact"), 10)
if (incImpact < highestImpact) {
highestImpact = incImpact
}
}
}
problem.setValue("impact", highestImpact)
problem.setValue("urgency", highestImpact)
// Assignment
if (problemData.assignmentGroup) {
problem.setValue("assignment_group", problemData.assignmentGroup)
}
// Affected CI
if (problemData.cmdb_ci) {
problem.setValue("cmdb_ci", problemData.cmdb_ci)
}
var problemSysId = problem.insert()
// Link incidents to problem
for (var j = 0; j < incidentSysIds.length; j++) {
var incidentToLink = new GlideRecord("incident")
if (incidentToLink.get(incidentSysIds[j])) {
incidentToLink.setValue("problem_id", problemSysId)
incidentToLink.work_notes = "Linked to Problem: " + problem.getValue("number")
incidentToLink.update()
}
}
return {
sys_id: problemSysId,
number: problem.getValue("number"),
}
}
```
### Proactive Problem Creation
```javascript
// Identify patterns for proactive problems (ES5 ONLY!)
function identifyProactiveProblems() {
var LOG_PREFIX = "[ProactiveProblem] "
var threshold = 5 // Minimum incidents to trigger
// Find recurring incident patterns
var ga = new GlideAggregate("incident")
ga.addQuery("opened_at", ">=", gs.daysAgo(30))
ga.addQuery("active", false) // Only closed incidents
ga.addNotNullQuery("cmdb_ci")
ga.addAggregate("COUNT")
ga.groupBy("cmdb_ci")
ga.groupBy("category")
ga.groupBy("subcategory")
ga.addHaving("COUNT", ">", threshold)
ga.orderByAggregate("COUNT", "DESC")
ga.query()
var patterns = []
while (ga.next()) {
var count = parseInt(ga.getAggregate("COUNT"), 10)
var ci = ga.getValue("cmdb_ci")
var category = ga.getValue("category")
var subcategory = ga.getValue("subcategory")
// Check if problem already exists
if (!problemExistsForPattern(ci, category, subcategory)) {
patterns.push({
cmdb_ci: ci,
ci_name: ga.cmdb_ci.getDisplayValue(),
category: category,
subcategory: subcategory,
incident_count: count,
})
gs.info(
LOG_PREFIX +
"Pattern found: " +
count +
" incidents for CI " +
ga.cmdb_ci.getDisplayValue() +
" (" +
category +
"/" +
subcategory +
")",
)
}
}
return patterns
}
function problemExistsForPattern(ci, category, subcategory) {
var problem = new GlideRecord("problem")
problem.addQuery("cmdb_ci", ci)
problem.addQuery("category", category)
problem.addQuery("subcategory", subcategory)
problem.addQuery("state", "NOT IN", "5,6,7") // Not resolved/closed/cancelled
problem.query()
return problem.hasNext()
}
```
## Root Cause Analysis (ES5)
### RCA Workflow
```javascript
// Start RCA process (ES5 ONLY!)
function startRootCauseAnalysis(problemSysId) {
var problem = new GlideRecord("problem")
if (!problem.get(problemSysId)) {
return false
}
// Move to RCA state
problem.setValue("state", 3) // Root Cause Analysis
problem.update()
// Create RCA tasks
var tasks = [
{ title: "Gather incident data", order: 100 },
{ title: "Interview stakeholders", order: 200 },
{ title: "Review system logs", order: 300 },
{ title: "Identify contributing factors", order: 400 },
{ title: "Document root cause", order: 500 },
]
for (var i = 0; i < tasks.length; i++) {
createProblemTask(problemSysId, tasks[i])
}
return true
}
function createProblemTask(problemSysId, taskData) {
var task = new GlideRecord("problem_task")
task.initialize()
task.setValue("problem", problemSysId)
task.setValue("short_description", taskData.title)
task.setValue("order", taskData.order)
task.setValue("state", 1) // New
return task.insert()
}
```
### Document Root Cause
```javascript
// Document RCA findings (ES5 ONLY!)
function documentRootCause(problemSysId, rcaData) {
var problem = new GlideRecord("problem")
if (!problem.get(problemSysId)) {
return false
}
// Set root cause fields
problem.setValue("cause_notes", rcaData.rootCause)
problem.setValue("u_contributing_factors", rcaData.contributingFactors)
// 5 Whys analysis
if (rcaData.fiveWhys) {
problem.setValue("u_five_whys", JSON.stringify(rcaData.fiveWhys))
}
// Set root cause category
problem.setValue("u_root_cause_category", rcaData.category)
// Document fix
problem.setValue("fix_notes", rcaData.proposedFix)
// Move to Fix in Progress if ready
if (rcaData.readyToFix) {
problem.setValue("state", 4) // Fix in Progress
}
problem.update()
// Add to work notes
problem.work_notes =
"Root Cause Documented:\n" +
"-------------------\n" +
rcaData.rootCause +
"\n\n" +
"Proposed Fix:\n" +
"-------------\n" +
rcaData.proposedFix
problem.update()
return true
}
```
## Known Error Database (ES5)
### Create Known Error
```javascript
// Create Known Error from Problem (ES5 ONLY!)
function createKnownError(problemSysId, workaroundInfo) {
var problem = new GlideRecord("problem")
if (!problem.get(problemSysId)) {
return null
}
// Create Known Error
var ke = new GlideRecord("known_error")
ke.initialize()
// Copy from problem
ke.setValue("short_description", problem.getValue("short_description"))
ke.setValue("description", problem.getValue("description"))
ke.setValue("cause_notes", problem.getValue("cause_notes"))
ke.setValue("cmdb_ci", problem.getValue("cmdb_ci"))
ke.setValue("category", problem.getValue("category"))
ke.setValue("subcategory", problem.getValue("subcategory"))
// Workaround
ke.setValue("workaround", workaroundInfo.description)
ke.setValue("u_workaround_effectiveness", workaroundInfo.effectiveness)
// Link to problem
ke.setValue("problem", problemSysId)
// Set state
ke.setValue("state", "published")
var keSysId = ke.insert()
// Update problem with known error link
problem.setValue("known_error", keSysId)
problem.setValue("known_error_state", "accepted")
problem.update()
return {
sys_id: keSysId,
number: ke.getValue("number"),
}
}
```
### Search Known Errors
```javascript
// Search KEDB for matching workarounds (ES5 ONLY!)
var KEDBSearch = Class.create()
KEDBSearch.prototype = {
initialize: function () {},
/**
* Find matching known errors for an incident
*/
findForIncident: function (incidentSysId) {
var incident = new GlideRecord("incident")
if (!incident.get(incidentSysId)) {
return []
}
var matches = []
// Search by CI
if (incident.cmdb_ci) {
var ciMatches = this._searchByCI(incident.getValue("cmdb_ci"))
matches = matches.concat(ciMatches)
}
// Search by category
var catMatches = this._searchByCategory(incident.getValue("category"), incident.getValue("subcategory"))
matches = matches.concat(catMatches)
// Search by keywords
var keywordMatches = this._searchByKeywords(incident.getValue("short_description"))
matches = matches.concat(keywordMatches)
// Deduplicate
return this._deduplicate(matches)
},
_searchByCI: function (ciSysId) {
var results = []
var ke = new GlideRecord("known_error")
ke.addQuery("cmdb_ci", ciSysId)
ke.addQuery("state", "published")
ke.query()
while (ke.next()) {
results.push(this._toObject(ke, "CI Match"))
}
return results
},
_searchByCategory: function (category, subcategory) {
var results = []
var ke = new GlideRecord("known_error")
ke.addQuery("category", category)
if (subcategory) {
ke.addQuery("subcategory", subcategory)
}
ke.addQuery("state", "published")
ke.query()
while (ke.next()) {
results.push(this._toObject(ke, "Category Match"))
}
return results
},
_searchByKeywords: function (description) {
var results = []
var keywords = description.split(" ").filter(function (w) {
return w.length > 3
})
var ke = new GlideRecord("known_error")
ke.addQuery("state", "published")
var qc = null
for (var i = 0; i < keywords.length && i < 5; i++) {
if (qc === null) {
qc = ke.addQuery("short_description", "CONTAINS", keywords[i])
} else {
qc.addOrCondition("short_description", "CONTAINS", keywords[i])
}
}
ke.query()
while (ke.next()) {
results.push(this._toObject(ke, "Keyword Match"))
}
return results
},
_toObject: function (gr, matchType) {
return {
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
title: gr.getValue("short_description"),
workaround: gr.getValue("workaround"),
matchType: matchType,
}
},
_deduplicate: function (matches) {
var seen = {}
var unique = []
for (var i = 0; i < matches.length; i++) {
if (!seen[matches[i].sys_id]) {
seen[matches[i].sys_id] = true
unique.push(matches[i])
}
}
return unique
},
type: "KEDBSearch",
}
```
## Problem Resolution (ES5)
### Resolve Problem
```javascript
// Resolve problem with fix (ES5 ONLY!)
function resolveProblem(problemSysId, resolutionData) {
var problem = new GlideRecord("problem")
if (!problem.get(problemSysId)) {
return { success: false, message: "Problem not found" }
}
// Validate
if (!resolutionData.fixNotes) {
return { success: false, message: "Fix notes required" }
}
// Update problem
problem.setValue("state", 5) // Resolved
problem.setValue("fix_notes", resolutionData.fixNotes)
problem.setValue("resolution_code", resolutionData.resolutionCode)
problem.setValue("resolved_at", new GlideDateTime())
problem.setValue("resolved_by", gs.getUserID())
// Link to change if permanent fix deployed
if (resolutionData.changeRequest) {
problem.setValue("rfc", resolutionData.changeRequest)
}
problem.update()
// Update related Known Error if exists
if (problem.known_error) {
var ke = new GlideRecord("known_error")
if (ke.get(problem.getValue("known_error"))) {
ke.setValue("state", "closed")
ke.setValue("u_permanent_fix", resolutionData.fixNotes)
ke.update()
}
}
// Notify incident owners
notifyLinkedIncidents(problemSysId, "Problem resolved: " + problem.getValue("number"))
return {
success: true,
number: problem.getValue("number"),
}
}
function notifyLinkedIncidents(problemSysId, message) {
var incident = new GlideRecord("incident")
incident.addQuery("problem_id", problemSysId)
incident.addQuery("active", true)
incident.query()
while (incident.next()) {
incident.work_notes = message
incident.update()
}
}
```
## MCP Tool Integration
### Available Tools
| Tool | Purpose |
| --------------------------------- | ------------------------------- |
| `snow_query_table` | Query problems and known errors |
| `snow_find_artifact` | Find problem records |
| `snow_execute_script_with_output` | Test problem scripts |
| `snow_create_business_rule` | Create problem automation |
### Example Workflow
```javascript
// 1. Find open problems
await snow_query_table({
table: "problem",
query: "active=true",
fields: "number,short_description,state,assignment_group",
})
// 2. Search KEDB
await snow_query_table({
table: "known_error",
query: "state=published^short_descriptionLIKEemail",
fields: "number,short_description,workaround",
})
// 3. Find recurring incidents for proactive problems
await snow_execute_script_with_output({
script: `
var patterns = identifyProactiveProblems();
gs.info('Patterns found: ' + patterns.length);
`,
})
```
## Best Practices
1. **Incident Linking** - Link all related incidents
2. **Root Cause Focus** - Find actual cause, not symptoms
3. **5 Whys Technique** - Drill down to root cause
4. **Known Errors** - Document workarounds
5. **Permanent Fixes** - Link to change requests
6. **Metrics** - Track problem resolution time
7. **Proactive** - Identify patterns before escalation
8. **ES5 Only** - No modern JavaScript syntax
More from serac-labs/serac
- acl-securityCreate and debug ServiceNow ACLs (record, field, REST, script-include). Covers role/condition/script patterns, evaluation order, field-level visibility, and impersonation testing for row- and field-level security.
- agent-workspaceBuild ServiceNow Agent Workspace configurations — workspaces, lists, forms, contextual side panels, Agent Assist similar-record finders, and workspace-specific UI actions on sys_aw_* tables.
- approval-workflowsConfigure ServiceNow approval rules and sysapproval_approver records — manager/group/script approvers, multi-level routing, delegation via sys_user_delegate, and parent-record state rollup.
- asset-managementManage ServiceNow hardware assets, software licenses, and lifecycle states on alm_hardware/alm_license — license allocation, CMDB-to-asset linking, warranty tracking, inventory aggregation (HAM/SAM).
- atf-testingBuild ServiceNow Automated Test Framework tests and suites — impersonation, form steps, assertions, server-side script steps, test parameters, and execution via snow_create_atf_test / snow_execute_atf_test.
- blast-radiusTrace ServiceNow configuration dependencies — what artifacts touch a given field, what calls a script include, table/app-level config inventory. Use before deletes, renames, or refactors.
- bun-file-ioUse this when you are working on file operations like reading, writing, scanning, or deleting files. It summarizes the preferred file APIs and patterns used in this repo. It also notes when to use filesystem helpers for directories.
- business-rule-patternsWrite ServiceNow business rules (before/after/async/display) — current vs previous, changesTo/changesFrom, recursion avoidance, setAbortAction, and async dispatch for heavy work.
- catalog-itemsBuild ServiceNow Service Catalog items, variables, variable sets, catalog client scripts, record producers, and order guides with reference qualifiers and dynamic pricing.
- client-scriptsWrite ServiceNow client scripts (onLoad/onChange/onSubmit/onCellEdit) using g_form, g_user, GlideAjax, field visibility/mandatory toggles, and validation with debounced server calls.