{"record":{"id":"dc067bf834de0b5a","repo":"jackwener/OpenCLI","slug":"expected-inbox-items-array-got-typeof-items-c","errorCode":null,"errorMessage":"expected inbox items array, got ${typeof items} (contract drift?)","messagePattern":"expected inbox items array, got (.+?) \\(contract drift\\?\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/slock/inbox.js","lineNumber":70,"sourceCode":"  func: async (page, kwargs) => {\n    const filter = String(kwargs.filter ?? 'all').toLowerCase();\n    if (!FILTERS.includes(filter)) {\n      throw new ArgumentError(`--filter must be one of ${FILTERS.join(' | ')} (got \"${filter}\")`);\n    }\n    const limit = parsePositiveInteger(kwargs.limit, '--limit', { defaultValue: 30, max: 100 });\n    const offset = parseNonNegativeInteger(kwargs.offset, '--offset', { defaultValue: 0 });\n    await page.goto(SLOCK_HOME_URL);\n    const snippet = buildFetchSnippet({\n      method: 'GET',\n      path: `/channels/inbox?filter=${encodeURIComponent(filter)}&limit=${limit}&offset=${offset}`,\n      serverScoped: true,\n      serverIdOverride: kwargs.server,\n    });\n    const result = await page.evaluate(`(async () => { ${snippet} })()`);\n    const data = dispatchEvaluateResult(result);\n    const items = Array.isArray(data) ? data : (data.items || []);\n    if (!Array.isArray(items)) {\n      throw new CommandExecutionError(`expected inbox items array, got ${typeof items} (contract drift?)`);\n    }\n    return items.map(mapItem);\n  },\n});\n","sourceCodeStart":52,"sourceCodeEnd":75,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/inbox.js#L52-L75","documentation":"clis/slock/inbox.js maps the result of an in-page evaluate to an inbox items array. It tolerates a bare array or an object with an `items` property, but if the normalized value is still not an array it throws this CommandExecutionError, meaning the server/response shape no longer matches the CLI's expected contract.","triggerScenarios":"Running `inbox` when page.evaluate returns a payload where dispatchEvaluateResult(data) yields neither an array nor an object with an `items` array field — e.g. the API changed its envelope, an error object leaked through dispatchEvaluateResult, or `data.items` itself is an object/null.","commonSituations":"Server API version drifted from what the CLI expects (envelope renamed from `items` to something else); an auth/permission failure returns an error object the dispatcher doesn't convert; a proxy returns HTML/JSON error bodies instead of the expected response.","solutions":["Update the slock CLI to match the current server response contract (check the /inbox endpoint envelope field name).","Log the raw `data` value before the throw to see what shape actually came back.","Verify authentication/active server is correct so the endpoint returns the real payload rather than an error object.","Retry after checking for server-side upgrades or breaking changes in release notes."],"exampleFix":"// before\nconst items = Array.isArray(data) ? data : (data.items || []);\n// after\nconst items = Array.isArray(data) ? data : (data.items || data.messages || data.entries || []);","handlingStrategy":"type-guard","validationCode":"const data = dispatchEvaluateResult(result);\nconst candidate = Array.isArray(data) ? data : data?.items;\nif (!Array.isArray(candidate)) throw new Error(`unexpected inbox payload: ${JSON.stringify(data).slice(0,200)}`);","typeGuard":"function isInboxItems(v) { return Array.isArray(v) || (v !== null && typeof v === 'object' && Array.isArray(v.items)); }","tryCatchPattern":"try { const items = await inbox(page, kwargs); } catch (e) { if (String(e.message).includes('expected inbox items array')) { console.error('Contract drift — inspect raw payload / update CLI'); } else throw e; }","preventionTips":["Pin CLI version to the server API version you run against","Log raw evaluate payloads once when integrating a new server","Wrap dispatchEvaluateResult results with array checks before mapping"],"tags":["contract-drift","response-shape","cli"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}