{"record":{"id":"cb070c2b18847936","repo":"jackwener/OpenCLI","slug":"slock-commandname-succeeded-without-returning-t","errorCode":null,"errorMessage":"Slock ${commandName} succeeded without returning task id ${expectedId}; refusing to report a task row.","messagePattern":"Slock (.+?) succeeded without returning task id (.+?); refusing to report a task row\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/slock/task-identity.js","lineNumber":6,"sourceCode":"import { CommandExecutionError } from '@jackwener/opencli/errors';\n\nexport function assertTaskIdentity(t, expectedId, commandName) {\n  const taskId = t?.id;\n  if (!taskId) {\n    throw new CommandExecutionError(`Slock ${commandName} succeeded without returning task id ${expectedId}; refusing to report a task row.`);\n  }\n  if (taskId !== expectedId) {\n    throw new CommandExecutionError(`Slock ${commandName} returned task id ${taskId}, expected ${expectedId}.`);\n  }\n  return taskId;\n}\n","sourceCodeStart":1,"sourceCodeEnd":13,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/task-identity.js#L1-L13","documentation":"assertTaskIdentity in clis/slock/task-identity.js is a post-condition guard: after a task command 'succeeds', it verifies the returned row actually carries an id. If the row has no id (undefined/null/empty), it refuses to report the row because reporting an unidentifiable task could silently act on the wrong record. This is deliberate defensive behavior against server contract drift.","triggerScenarios":"A slock command (get/update/delete/status) resolves successfully but the API response row `t` is null/undefined, is not an object, or lacks the `id` field, e.g. after an API schema change where the field was renamed or the endpoint returns an error payload shaped like success.","commonSituations":"Slock API version bump renaming `id` to `taskId`; a proxy returning an HTML error page parsed into an unexpected object; stale auth causing the server to return an empty payload with 200; unit fixtures missing the id field.","solutions":["Log the raw response body from the slock API to see what shape was actually returned","Check whether the slock API version changed and the task id field was renamed (e.g. to taskId); update row mapping","Confirm authentication is valid — an empty 200 response often means the session/headers were rejected","Update the command's row-mapping code to map the new field name onto `id`, or pin the working API version"],"exampleFix":"// before (mapping drops the new field name)\nconst row = { taskNumber: t.taskNumber, title: t.title };\nassertTaskIdentity(row, expectedId, 'task-get');\n// after\nconst row = { id: t.id ?? t.taskId, taskNumber: t.taskNumber, title: t.title };\nassertTaskIdentity(row, expectedId, 'task-get');","handlingStrategy":"type-guard","validationCode":"if (response == null || typeof response !== 'object' || !('id' in response)) {\n  // inspect raw payload before calling assertTaskIdentity\n}","typeGuard":"const hasTaskId = (t) => t != null && typeof t === 'object' && typeof t.id === 'string' && t.id.length > 0;","tryCatchPattern":"try {\n  assertTaskIdentity(row, expectedId, 'task-get');\n} catch (e) {\n  console.error('Task row missing id; raw payload:', JSON.stringify(rawPayload));\n  throw e;\n}","preventionTips":["Map every known id-field alias (id, taskId, _id) onto `id` when parsing rows","Log raw API payloads when upgrading the slock server to catch schema drift early","Keep a contract test asserting the API returns an id field"],"tags":["contract-drift","api-response","defensive-check"],"backgroundTag":"api-response-shape-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}