{"record":{"id":"25d0bf1d7e229881","repo":"thedotmack/claude-mem","slug":"invalid-operation","errorCode":null,"errorMessage":"Invalid operation","messagePattern":"Invalid operation","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"src/services/server/Server.ts","lineNumber":298,"sourceCode":"          message: 'Worker is still initializing, please retry',\n        });\n      }\n    });\n\n    this.app.get('/api/version', (_req: Request, res: Response) => {\n      res.status(200).json({ version: BUILT_IN_VERSION });\n    });\n\n    this.app.get('/api/instructions', (req: Request, res: Response) => {\n      const topic = (req.query.topic as string) || 'all';\n      const operation = req.query.operation as string | undefined;\n\n      if (topic && !ALLOWED_TOPICS.includes(topic)) {\n        return res.status(400).json({ error: 'Invalid topic' });\n      }\n\n      if (operation && !ALLOWED_OPERATIONS.includes(operation)) {\n        return res.status(400).json({ error: 'Invalid operation' });\n      }\n\n      if (operation) {\n        const cached = cachedOperationContent.get(operation);\n        if (cached === undefined) {\n          logger.debug('HTTP', 'Instruction file not cached at boot', { operation });\n          return res.status(404).json({ error: 'Instruction not found' });\n        }\n        return res.json({ content: [{ type: 'text', text: cached }] });\n      }\n\n      if (cachedSkillMd === null) {\n        logger.debug('HTTP', 'SKILL.md not cached at boot', { topic });\n        return res.status(404).json({ error: 'Instruction not found' });\n      }\n      const sectionText = this.extractInstructionSection(cachedSkillMd, topic);\n      res.json({ content: [{ type: 'text', text: sectionText }] });\n    });","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/8bc631a71a487424b866756e43a6efa4574cc66b/src/services/server/Server.ts#L280-L316","documentation":"GET /api/instructions validates the operation query parameter against the ALLOWED_OPERATIONS allow-list; a value outside the list returns 400 'Invalid operation'. The topic check runs first, so a bad topic masks a bad operation with 'Invalid topic'.","triggerScenarios":"GET /api/instructions?operation=<value> where value is not an allowed operation name — invented names, typos, or operations added/removed in a different server version.","commonSituations":"Tooling hardcoding operation names that drift across releases; mixing up topic and operation parameters; copied URLs from docs for a different version.","solutions":["Use an operation name from ALLOWED_OPERATIONS exactly","If you want topical content rather than an operation, use ?topic= instead","Inspect ALLOWED_OPERATIONS in the server source for the current list"],"exampleFix":"// before\nfetch(`${base}/api/instructions?operation=summarize-all`); // 400 Invalid operation\n\n// after\nfetch(`${base}/api/instructions?operation=summarize`); // 200","handlingStrategy":"validation","validationCode":"const ALLOWED_OPERATIONS = new Set([/* mirror ALLOWED_OPERATIONS from the server */ 'summarize', 'recall']);\n\nfunction operationUrl(base: string, operation: string): string | null {\n  if (!ALLOWED_OPERATIONS.has(operation)) return null; // skip the call entirely\n  return `${base}/api/instructions?operation=${encodeURIComponent(operation)}`;\n}","typeGuard":"function isInvalidParameter(status: number, body: unknown, field: 'topic' | 'operation'): body is { error: string } {\n  return status === 400 && typeof body === 'object' && body !== null && (body as { error?: string }).error === `Invalid ${field}`;\n}","tryCatchPattern":"const res = await fetch(`${base}/api/instructions?operation=${op}`);\nif (res.status === 400) {\n  const body = await res.json().catch(() => ({}));\n  if (body.error === 'Invalid operation') throw new Error(`operation \"${op}\" not supported by this server version`);\n  if (body.error === 'Invalid topic') throw new Error('topic param is also wrong — fix it first');\n  throw new Error(`unexpected 400: ${JSON.stringify(body)}`);\n}","preventionTips":["Verify operation names against ALLOWED_OPERATIONS for your server version","Do not confuse ?topic= and ?operation= — they validate against different lists","Feature-detect operations at startup rather than assuming availability"],"tags":["query-parameters","http-400","instructions"],"backgroundTag":"invalid-query-parameter","analyzedSha":"8bc631a71a487424b866756e43a6efa4574cc66b","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}