{"record":{"id":"6658d3ef9771db7c","repo":"toeverything/AFFiNE","slug":"invalid-duration-string-unit-ch","errorCode":null,"errorMessage":"Invalid duration string unit ${ch}","messagePattern":"Invalid duration string unit (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/backend/server/src/base/utils/duration.ts","lineNumber":39,"sourceCode":"  109: 'm',\n  115: 's',\n};\n\nfunction parse(str: string): DurationInput {\n  let input: DurationInput = {};\n\n  let acc = 0;\n  for (let i = 0; i < str.length; i++) {\n    const ch = str[i];\n    const code = ch.charCodeAt(0);\n\n    // number [0..9]\n    if (code >= 48 && code <= 57) {\n      acc = acc * 10 + code - 48;\n    } else {\n      let unit = KnownCharCodeToCharMap[code];\n      if (!unit) {\n        throw new Error(`Invalid duration string unit ${ch}`);\n      }\n\n      // look ahead a char for 'ms' checking if unit met 'm'\n      if (unit === 'm' && str[i + 1] === 's') {\n        unit = 'ms';\n        i++;\n      }\n\n      input[unit] = acc;\n      acc = 0;\n    }\n  }\n\n  return input;\n}\n\nexport const Due = {\n  ms: (dueStr: string | DurationInput) => {","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/base/utils/duration.ts#L21-L57","documentation":"Thrown by the parse() function in the duration utility when it encounters a character that is not a digit (0-9) and not a recognized duration unit letter. Recognized unit letters are: d (day), w (week), M (month), y (year), h (hour), m (minute), s (second), and the special case 'ms' (milliseconds). Any other character after a number triggers this error.","triggerScenarios":"Calling Due.ms(str), Due.s(str), Due.after(str), or Due.before(str) with a duration string containing an invalid unit character. For example: '5x' (x is not a unit), '10sec' (sec is not recognized — only 's' is), '3min' (min is not recognized — only 'm' is).","commonSituations":"Passing human-readable duration strings with full word units ('minutes', 'hours', 'days') instead of single-letter abbreviations. Using uppercase letters incorrectly (the parser is case-sensitive: 'M' is month, 'm' is minute, but 'H' or 'S' are not recognized). Typo in a duration string from config or user input.","solutions":["Use single-letter unit abbreviations: d, w, M (month), y, h, m (minute), s, ms.","Remember the parser is case-sensitive: 'M' = month, 'm' = minute, 's' = second, 'ms' = millisecond.","Validate duration strings before passing them to the Due functions, or wrap calls in try-catch.","Alternatively, pass a DurationInput object directly instead of a string (e.g. { h: 1, m: 30 })."],"exampleFix":"// before\nDue.ms('5min'); // 'min' -> 'n' is not a unit -> throws\nDue.ms('2H'); // uppercase H not recognized -> throws\n\n// after\nDue.ms('5m'); // 5 minutes\nDue.ms('2h'); // 2 hours\n// or pass an object\nDue.ms({ minutes: 5 }); // note: key is 'm' not 'minutes'","handlingStrategy":"validation","validationCode":"const VALID_UNITS = /^[\\d]+(ms|[dwMyhms])/;\nfunction isValidDuration(str: string): boolean {\n  // split into number-unit pairs and validate each\n  return str.split(/(?<=\\D)(?=\\d)/).every(part => VALID_UNITS.test(part));\n}\nif (!isValidDuration(durationStr)) {\n  throw new Error(`Invalid duration string: ${durationStr}`);\n}\nDue.ms(durationStr);","typeGuard":"const isParsableDuration = (str: string): boolean => {\n  try {\n    Due.parse(str);\n    return true;\n  } catch {\n    return false;\n  }\n};","tryCatchPattern":"try {\n  const ms = Due.ms(durationStr);\n} catch (e) {\n  if (e.message?.includes('Invalid duration string unit')) {\n    // parse failed; use a default duration or prompt user\n    const ms = Due.ms('1h'); // fallback\n  }\n}","preventionTips":["Use single-letter unit abbreviations: d, w, M, y, h, m, s, ms.","Remember case sensitivity: 'M' is month, 'm' is minute.","Prefer passing a DurationInput object for programmatic calls to avoid string parsing errors.","Wrap Due.parse in a try-catch or use a validation helper when accepting user input."],"tags":["affine-backend","utils","duration","parsing","validation"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}