{"record":{"id":"5d859e33bf86fa50","repo":"ComposioHQ/composio","slug":"use-only-one-of-before-or-after","errorCode":null,"errorMessage":"Use only one of before or after.","messagePattern":"Use only one of before or after\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"ts/packages/cli-local-tools/src/toolkits/beeper-imessage.ts","lineNumber":158,"sourceCode":"  return messages[0];\n};\n\nconst buildGlobalArgs = (input: Record<string, unknown>): string[] => {\n  const args: string[] = [];\n  const dataDir = optionalString(input.dataDir);\n  if (dataDir) args.push('--data-dir', dataDir);\n  if (input.useSecondaryInstance === false) args.push('--no-use-secondary-instance');\n  // Local tools are one-shot calls. Avoid keeping DB event watchers open unless a\n  // future streaming tool explicitly opts in.\n  args.push('--no-events');\n  if (input.verbose === true) args.push('--verbose');\n  return args;\n};\n\nconst withCursorArgs = (input: Record<string, unknown>, args: string[]): string[] => {\n  const before = optionalString(input.before);\n  const after = optionalString(input.after);\n  if (before && after) throw new Error('Use only one of before or after.');\n  if (before) args.push('--before', before);\n  if (after) args.push('--after', after);\n  return args;\n};\n\nconst stripAnsi = (text: string): string => text.replace(/\\x1B\\[[0-?]*[ -/]*[@-~]/g, '');\n\nconst parseImessageCliOutput = (\n  commandName: string,\n  stdout: string,\n  stderr: string\n): LocalExecutionResult => {\n  const cleanStdout = stripAnsi(stdout);\n  const lines = cleanStdout.split(/\\r?\\n/);\n  const okIndex = lines.findIndex(line => /^\\[\\d+\\] ok /.test(line));\n  const okLine = okIndex >= 0 ? lines[okIndex] : undefined;\n  const match = okLine?.match(/^\\[(\\d+)\\] ok \\S+ \\((\\d+(?:\\.\\d+)?)ms\\)$/);\n","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/cli-local-tools/src/toolkits/beeper-imessage.ts#L140-L176","documentation":"The beeper-imessage thread listing tools accept before and after cursors for pagination, but they are mutually exclusive — you may pass at most one. Passing both is rejected because the underlying CLI cannot apply two conflicting cursor directions at once.","triggerScenarios":"Calling page/raw list tools with both input.before and input.after set, e.g. copying a pagination loop that fills both cursors; LLM tool calls that populate every optional field.","commonSituations":"Auto-generated tool calls from LLMs filling all optional params; refactors that merge two pagination calls into one.","solutions":["Pass only one cursor: before OR after","Clear the opposite field when reusing a params object across pages","Use the returned next-cursor value for the next page rather than tracking both"],"exampleFix":"// before\nraw({ before: 'cursorA', after: 'cursorB', limit: 50 });\n// after\nraw({ after: 'cursorB', limit: 50 });","handlingStrategy":"validation","validationCode":"const hasBoth = input.before != null && input.after != null;\nif (hasBoth) throw new RangeError('pick one cursor');","typeGuard":"const singleCursor = (i: { before?: string; after?: string }) =>\n  (i.before ? 1 : 0) + (i.after ? 1 : 0) <= 1;","tryCatchPattern":"try { ... } catch (e) { if (e.message === 'Use only one of before or after.') dropOneCursorAndRetry(); }","preventionTips":["Pass only the cursor returned by the previous page","Delete stale cursor fields when reusing param objects"],"tags":["pagination","local-tools","imessage","validation"],"backgroundTag":"mutually-exclusive-params","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}