{"record":{"id":"c0352767218dd745","repo":"jackwener/OpenCLI","slug":"twitter-collection-until-must-be-an-rfc3339-time","errorCode":null,"errorMessage":"twitter collection --until must be an RFC3339 timestamp","messagePattern":"twitter collection --until must be an RFC3339 timestamp","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/twitter/collection.js","lineNumber":28,"sourceCode":"    DEFAULT_USER_TWEETS_PAGE_DELAY_SECONDS,\n    MAX_USER_TWEETS_LIMIT,\n    MAX_USER_TWEETS_PAGES,\n    USER_TWEETS_PAGE_SIZE,\n    fetchUserTimelinePage,\n    resolveUserTimelineContext,\n} from './user-timeline.js';\n\nconst RFC3339_TIMESTAMP = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?(Z|([+-])(\\d{2}):(\\d{2}))$/;\n\nfunction isLeapYear(year) {\n    return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n}\n\nfunction normalizeUntil(raw) {\n    const value = String(raw ?? '').trim();\n    const match = value.match(RFC3339_TIMESTAMP);\n    if (!match) {\n        throw new ArgumentError(\n            'twitter collection --until must be an RFC3339 timestamp',\n            'Example: opencli twitter collection @jack --until 2026-07-23T00:00:00Z',\n        );\n    }\n    const [, yearRaw, monthRaw, dayRaw, hourRaw, minuteRaw, secondRaw, , zone, , offsetHourRaw, offsetMinuteRaw] = match;\n    const year = Number(yearRaw);\n    const month = Number(monthRaw);\n    const day = Number(dayRaw);\n    const hour = Number(hourRaw);\n    const minute = Number(minuteRaw);\n    const second = Number(secondRaw);\n    const offsetHour = zone === 'Z' ? 0 : Number(offsetHourRaw);\n    const offsetMinute = zone === 'Z' ? 0 : Number(offsetMinuteRaw);\n    const daysInMonth = month === 2\n        ? (isLeapYear(year) ? 29 : 28)\n        : ([4, 6, 9, 11].includes(month) ? 30 : 31);\n    if (\n        month < 1 || month > 12","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/collection.js#L10-L46","documentation":"normalizeUntil validates the --until flag against an RFC3339 timestamp regex before any numeric or Date checks; a string that doesn't match the RFC3339 shape fails immediately with usage guidance. This ensures the flag is parseable as an exact instant before further validation.","triggerScenarios":"Calling `opencli twitter collection @user --until` with a value that fails the RFC3339_TIMESTAMP regex, e.g. '2026-07-23', 'yesterday', '2026/07/23 00:00', or an empty string.","commonSituations":"Users typing date-only values or human phrases like 'now'/'last week'; shell scripts interpolating epoch integers; copy-pasted timestamps with locale formats or missing timezone designators.","solutions":["Pass a full RFC3339 timestamp such as 2026-07-23T00:00:00Z","Include a timezone (Z or ±hh:mm offset) — date-only strings will not match","Convert from your local/epoch format first, e.g. new Date(...).toISOString()","Use the suggested example from the error hint verbatim as a template"],"exampleFix":"// before\n--until 2026-07-23\n// after\n--until 2026-07-23T00:00:00Z","handlingStrategy":"validation","validationCode":"function isRfc3339(s) {\n  return typeof s === 'string' && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/.test(s.trim());\n}\nif (!isRfc3339(until)) throw new Error(`--until must be RFC3339, got: ${until}`);","typeGuard":"function isRfc3339Timestamp(v) {\n  return typeof v === 'string' && !Number.isNaN(new Date(v).getTime()) && /^\\d{4}-\\d{2}-\\d{2}T/.test(v);\n}","tryCatchPattern":"try {\n  await run(['opencli','twitter','collection',handle,'--until',until]);\n} catch (err) {\n  if (String(err.message).includes('--until must be an RFC3339 timestamp')) {\n    until = new Date(until).toISOString(); // retry with canonical form\n  } else throw err;\n}","preventionTips":["Always emit timestamps via new Date(...).toISOString() in scripts","Never pass date-only strings or natural-language times to --until","Include the timezone designator (Z or ±hh:mm) explicitly","Validate the flag with a regex before invoking the CLI"],"tags":["twitter","cli","validation","rfc3339","timestamp"],"backgroundTag":"invalid-timestamp-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}