{"record":{"id":"9afaad6dec730c49","repo":"mozilla/pdf.js","slug":"first-argument-of-printf-must-be-a-string","errorCode":null,"errorMessage":"First argument of printf must be a string","messagePattern":"First argument of printf must be a string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/scripting_api/util.js","lineNumber":70,"sourceCode":"\n  MILLISECONDS_IN_DAY = 86400000;\n\n  MILLISECONDS_IN_WEEK = 604800000;\n\n  constructor(data) {\n    super(data);\n\n    // used with crackURL\n    this._externalCall = data.externalCall;\n  }\n\n  printf(...args) {\n    if (args.length === 0) {\n      throw new Error(\"Invalid number of params in printf\");\n    }\n\n    if (typeof args[0] !== \"string\") {\n      throw new TypeError(\"First argument of printf must be a string\");\n    }\n\n    // eslint-disable-next-line regexp/no-misleading-capturing-group\n    const pattern = /%(,[0-4])?([+ 0#]+)?(\\d+)?(\\.\\d+)?(.)/g;\n    const PLUS = 1;\n    const SPACE = 2;\n    const ZERO = 4;\n    const HASH = 8;\n    let i = 0;\n    return args[0].replaceAll(\n      pattern,\n      function (_, nDecSep, cFlags, nWidth, nPrecision, cConvChar) {\n        // cConvChar must be one of d, f, s, x\n        if (\n          cConvChar !== \"d\" &&\n          cConvChar !== \"f\" &&\n          cConvChar !== \"s\" &&\n          cConvChar !== \"x\"","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/scripting_api/util.js#L52-L88","documentation":"Thrown by `Util.printf()` (src/scripting_api/util.js:70) as a `TypeError` when the first argument is present but not a string. The first argument is the format template containing `%d`, `%f`, `%s`, `%x` conversion specifiers; only strings can carry those specifiers.","triggerScenarios":"Calling `util.printf(42, ...)`, `util.printf(someObject, ...)`, or passing a number that was meant to be the first converted value but landed in the format slot because the real format string was dropped.","commonSituations":"Argument-shift bugs where the format string was omitted but values were kept; building the format from a non-string concatenation that produced a number; mis-ordered variadic spreads.","solutions":["Ensure the first argument is always a string literal or `String(x)`.","Coerce defensively: `util.printf(String(fmt), ...rest)`.","Add a type check at the call site and bail out early if `fmt` is not a string."],"exampleFix":"// before\nutil.printf(value, '%d'); // format string in the wrong slot\n// after\nutil.printf('%d', value);","handlingStrategy":"type-guard","validationCode":"function printfSafe(util, fmt, ...rest) {\n  if (typeof fmt !== 'string') return String(fmt ?? '');\n  return util.printf(fmt, ...rest);\n}","typeGuard":"function isFormatString(args) {\n  return args.length > 0 && typeof args[0] === 'string';\n}","tryCatchPattern":null,"preventionTips":["Make the first printf argument a string literal or String(x).","Double-check argument order when spreading variadic arrays.","Coerce defensively at the call boundary when the format is dynamic."],"tags":["scripting-api","util","printf","type-check","acrobat-js"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}