jackwener/OpenCLI · error · CommandExecutionError
Slock ${commandName} succeeded without returning task id ${e
Error message
Slock ${commandName} succeeded without returning task id ${expectedId}; refusing to report a task row. What it means
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.
Source
Thrown at clis/slock/task-identity.js:6
import { CommandExecutionError } from '@jackwener/opencli/errors';
export function assertTaskIdentity(t, expectedId, commandName) {
const taskId = t?.id;
if (!taskId) {
throw new CommandExecutionError(`Slock ${commandName} succeeded without returning task id ${expectedId}; refusing to report a task row.`);
}
if (taskId !== expectedId) {
throw new CommandExecutionError(`Slock ${commandName} returned task id ${taskId}, expected ${expectedId}.`);
}
return taskId;
}
View on GitHub (pinned to 49907e53dc)
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
Example fix
// before (mapping drops the new field name)
const row = { taskNumber: t.taskNumber, title: t.title };
assertTaskIdentity(row, expectedId, 'task-get');
// after
const row = { id: t.id ?? t.taskId, taskNumber: t.taskNumber, title: t.title };
assertTaskIdentity(row, expectedId, 'task-get'); Defensive patterns
Strategy: type-guard
Validate before calling
if (response == null || typeof response !== 'object' || !('id' in response)) {
// inspect raw payload before calling assertTaskIdentity
} Type guard
const hasTaskId = (t) => t != null && typeof t === 'object' && typeof t.id === 'string' && t.id.length > 0;
Try / catch
try {
assertTaskIdentity(row, expectedId, 'task-get');
} catch (e) {
console.error('Task row missing id; raw payload:', JSON.stringify(rawPayload));
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- expected array of rows from server, got ${typeof rows} (cont
- expected array of rows from server, got ${typeof rows} (cont
- Slock task-status succeeded without returning task id ${expe
- expected array of summary rows, got ${typeof rows} (contract
- Bilibili ${label} API returned a malformed payload
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/cb070c2b18847936.
Report an issue: GitHub.