{"record":{"id":"58ddc9462a3a6eb0","repo":"affaan-m/ECC","slug":"skill-execution-payload-must-be-an-object","errorCode":null,"errorMessage":"skill execution payload must be an object","messagePattern":"skill execution payload must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/skill-evolution/tracker.js","lineNumber":47,"sourceCode":"  return path.join(resolveHomeDir(options.homeDir), '.claude', 'state', 'skill-runs.jsonl');\n}\n\nfunction toNullableNumber(value, fieldName) {\n  if (value === null || typeof value === 'undefined') {\n    return null;\n  }\n\n  const numericValue = Number(value);\n  if (!Number.isFinite(numericValue)) {\n    throw new Error(`${fieldName} must be a number`);\n  }\n\n  return numericValue;\n}\n\nfunction normalizeExecutionRecord(input, options = {}) {\n  if (!input || typeof input !== 'object' || Array.isArray(input)) {\n    throw new Error('skill execution payload must be an object');\n  }\n\n  const skillId = input.skill_id || input.skillId;\n  const skillVersion = input.skill_version || input.skillVersion;\n  const taskDescription = input.task_description || input.task_attempted || input.taskAttempted;\n  const outcome = input.outcome;\n  const recordedAt = input.recorded_at || options.now || new Date().toISOString();\n  const userFeedback = input.user_feedback || input.userFeedback || null;\n\n  if (typeof skillId !== 'string' || skillId.trim().length === 0) {\n    throw new Error('skill_id is required');\n  }\n\n  if (typeof skillVersion !== 'string' || skillVersion.trim().length === 0) {\n    throw new Error('skill_version is required');\n  }\n\n  if (typeof taskDescription !== 'string' || taskDescription.trim().length === 0) {","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/skill-evolution/tracker.js#L29-L65","documentation":"Thrown first in normalizeExecutionRecord when the input is not a plain object: null, undefined, a primitive, or an array all fail. This is the entry guard before any field is read.","triggerScenarios":"recordSkillRun(null); recordSkillRun('{\"skill_id\":...}') (passing a JSON string instead of parsing it); recordSkillRun([record1, record2]) (passing an array); recordSkillRun(JSON.parse(badData)) where parse yielded a non-object.","commonSituations":"Forgetting JSON.parse on a serialized payload; forwarding a raw network body string; passing a collection instead of a single record.","solutions":["Pass a single parsed plain object.","If data may be a string, JSON.parse first and assert typeof === 'object' && !Array.isArray.","Loop over arrays and record one at a time."],"exampleFix":"// before\nrecordSkillRun(rawJsonString);\n\n// after\nconst parsed = JSON.parse(rawJsonString);\nrecordSkillRun(parsed);","handlingStrategy":"type-guard","validationCode":"function asRecord(input) {\n  if (typeof input === 'string') input = JSON.parse(input);\n  if (!input || typeof input !== 'object' || Array.isArray(input)) {\n    throw new TypeError('expected a single record object');\n  }\n  return input;\n}\nrecordSkillRun(asRecord(raw));","typeGuard":"function isPlainObject(v) {\n  return v != null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  recordSkillRun(input);\n} catch (err) {\n  if (/payload must be an object/.test(err.message)) {\n    recordSkillRun(JSON.parse(input));\n  } else throw err;\n}","preventionTips":["Always JSON.parse network/serialized payloads before recording.","Loop over arrays and record one record per call.","Assert the parsed shape at the trust boundary."],"tags":["tracker","payload","validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}