{"record":{"id":"bc4c56a71e708793","repo":"jackwener/OpenCLI","slug":"http-r-status-from-r-where","errorCode":null,"errorMessage":"HTTP ${r.status} from ${r.where}","messagePattern":"HTTP (.+?) from (.+?)","errorType":"http","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/slock/errors.js","lineNumber":18,"sourceCode":"import { ArgumentError, AuthRequiredError, CommandExecutionError, ConfigError } from '@jackwener/opencli/errors';\nimport { SLOCK_DOMAIN } from './shared.js';\n\n// EvaluateResult is the envelope every in-page snippet returns. Kinds:\n//   { kind: 'ok', rows, meta? }\n//   { kind: 'auth', detail }\n//   { kind: 'http', status, where }\n//   { kind: 'no-server', detail }\n//   { kind: 'unresolvable', detail }\n//   { kind: 'no-thread', parent }       // handled by caller, never reaches dispatcher\nexport function dispatchEvaluateResult(r) {\n  switch (r && r.kind) {\n    case 'ok':\n      return r.rows;\n    case 'auth':\n      throw new AuthRequiredError(SLOCK_DOMAIN, r.detail);\n    case 'http':\n      throw new CommandExecutionError(`HTTP ${r.status} from ${r.where}`);\n    case 'no-server':\n      throw new ConfigError(r.detail, 'Run `opencli slock server-use <slug>` to set the active server.');\n    case 'unresolvable':\n      throw new ArgumentError(r.detail);\n    case 'no-thread':\n      // caller decides what to do (returns a 0-row hint); should never reach here\n      throw new CommandExecutionError(`no-thread should be handled by caller, not dispatcher: ${r.parent}`);\n    default:\n      // unknown / null envelope = contract drift; fail loud (reddit precedent)\n      throw new CommandExecutionError(`unexpected evaluate envelope: ${JSON.stringify(r)}`);\n  }\n}\n","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/errors.js#L1-L31","documentation":"dispatchEvaluateResult maps an 'http' envelope to CommandExecutionError with the message `HTTP <status> from <where>`. The in-page fetch to the slock API returned a non-2xx status and the snippet surfaced it with the status code and the endpoint/where it happened.","triggerScenarios":"Any slock command whose snippet fetch returns 4xx/5xx: 403 (no permission to the channel), 404 (channel id doesn't exist), 429 (rate limit), 500 (server error).","commonSituations":"Referencing a #name that resolves to a deleted channel; lacking membership/permission for a private channel; hitting API rate limits with high --limit/pagination loops.","solutions":["Read the HTTP status in the message: 403/404 usually means wrong or forbidden channel — verify the channelId/#name","Retry after a delay if the status is 429 or 5xx (transient)","Check your membership in the target channel in the slock web app before rerunning"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// pre-verify the channel exists and is accessible:\nconst members = await runChannelMembers(channel); // 404/403 here means fix the channel first","typeGuard":"const isHttpError = (e) => e instanceof CommandExecutionError && /^HTTP \\d{3}/.test(e.message);","tryCatchPattern":"try { return await slockCommand(); } catch (e) { if (isHttpError(e) && /(429|5\\d\\d)/.test(e.message)) { await sleep(2000); return retry(slockCommand, 3); } throw e; }","preventionTips":["Verify channel ids/#names exist before calling","Reduce --limit / add delays when paginating to avoid 429s","Check channel membership/permissions in the web app for 403s"],"tags":["http","api-error","network"],"backgroundTag":"http-4xx-api-error","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}