{"record":{"id":"823370f882813e56","repo":"jackwener/OpenCLI","slug":"weread-official-api-name-is-required","errorCode":null,"errorMessage":"weread-official: api_name is required","messagePattern":"weread-official: api_name is required","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/weread-official/utils.js","lineNumber":54,"sourceCode":"export function getApiKey() {\n    const key = String(process.env.WEREAD_API_KEY ?? '').trim();\n    if (!key) {\n        throw new AuthRequiredError(\n            WEREAD_DOMAIN,\n            'WEREAD_API_KEY is not set. Export it with `export WEREAD_API_KEY=<wrk-...>`.',\n        );\n    }\n    return key;\n}\n\n/**\n * Build the gateway request body. Business params are flattened next to\n * `api_name` and `skill_version` — never wrapped in a `params` / `data` /\n * `body` object (the gateway silently drops them and returns page 1).\n */\nexport function buildGatewayBody(apiName, params = {}) {\n    if (!apiName || typeof apiName !== 'string') {\n        throw new ArgumentError('weread-official: api_name is required');\n    }\n    const body = { api_name: apiName, skill_version: SKILL_VERSION };\n    for (const [key, value] of Object.entries(params ?? {})) {\n        if (value === undefined || value === null || value === '') continue;\n        body[key] = value;\n    }\n    return body;\n}\n\n/**\n * POST to the agent gateway. Returns the parsed JSON payload on success.\n * Maps every documented failure mode to a typed CliError:\n *   - missing env key            → AuthRequiredError\n *   - HTTP non-2xx               → CommandExecutionError\n *   - network timeout            → TimeoutError\n *   - response includes upgrade_info → CommandExecutionError (with version hint)\n *   - errcode in AUTH_ERRCODES   → AuthRequiredError (Bearer key likely revoked)\n *   - errcode != 0               → CommandExecutionError","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weread-official/utils.js#L36-L72","documentation":"buildGatewayBody validates that api_name is a non-empty string before assembling the gateway request body. The WeRead gateway routes on api_name, so a missing/invalid value makes the request meaningless. The function throws ArgumentError to fail fast instead of sending a malformed request the gateway would silently mishandle.","triggerScenarios":"Calling buildGatewayBody(null/undefined/''/non-string) directly, or indirectly via callGateway or the tasks/payload/bookmarks/reviews helpers when the API name constant was not passed through (e.g. a typo'd variable or undefined argument from an upstream command handler).","commonSituations":"Refactoring a CLI command and dropping the apiName argument; wiring a new subcommand that forgets to pass the endpoint name; JavaScript callers passing a number or an object instead of the endpoint string.","solutions":["Pass the exact gateway api_name string (e.g. 'book.search') as the first argument to buildGatewayBody.","Check the calling helper to ensure it forwards its apiName parameter instead of an undefined variable.","Coerce or validate the api name at the command-handler layer before reaching the gateway helpers.","Log the apiName value just before the call to confirm it is a non-empty string."],"exampleFix":"// before\nbuildGatewayBody(opts.api, { query });\n// after\nif (typeof opts.api !== 'string' || !opts.api) throw new Error('api_name required');\nbuildGatewayBody(opts.api, { query });","handlingStrategy":"validation","validationCode":"if (typeof apiName !== 'string' || !apiName.trim()) throw new Error('api_name must be a non-empty string before calling buildGatewayBody');","typeGuard":"const isApiName = (v) => typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":"try {\n  const body = buildGatewayBody(apiName, params);\n} catch (e) {\n  if (e.name === 'ArgumentError') {\n    console.error(`Bad api_name: ${JSON.stringify(apiName)} — supply the gateway endpoint string`);\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Keep api names as named constants, not inline strings","Type the apiName parameter (JSDoc/TS string literal union) so undefined is caught early","Validate arguments at the CLI entry point before reaching gateway helpers"],"tags":["argument-validation","api-request"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}