{"record":{"id":"fea8a06d0287a202","repo":"mozilla/pdf.js","slug":"second-argument-of-app-setinterval-must-be-a-numbe","errorCode":null,"errorMessage":"Second argument of app.setInterval must be a number","messagePattern":"Second argument of app\\.setInterval must be a number","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/scripting_api/app.js","lineNumber":618,"sourceCode":"      cDefault = cQuestion.cDefault;\n      cQuestion = cQuestion.cQuestion;\n    }\n    cQuestion = (cQuestion || \"\").toString();\n    cDefault = (cDefault || \"\").toString();\n    return this._externalCall(\"prompt\", [cQuestion, cDefault || \"\"]);\n  }\n\n  setInterval(cExpr, nMilliseconds = 0) {\n    if (cExpr && typeof cExpr === \"object\") {\n      nMilliseconds = cExpr.nMilliseconds || 0;\n      cExpr = cExpr.cExpr;\n    }\n\n    if (typeof cExpr !== \"string\") {\n      throw new TypeError(\"First argument of app.setInterval must be a string\");\n    }\n    if (typeof nMilliseconds !== \"number\") {\n      throw new TypeError(\n        \"Second argument of app.setInterval must be a number\"\n      );\n    }\n    const callbackId = this._registerTimeoutCallback(cExpr);\n    this._externalCall(\"setInterval\", [callbackId, nMilliseconds]);\n    return this._registerTimeout(callbackId, true);\n  }\n\n  setTimeOut(cExpr, nMilliseconds = 0) {\n    if (cExpr && typeof cExpr === \"object\") {\n      nMilliseconds = cExpr.nMilliseconds || 0;\n      cExpr = cExpr.cExpr;\n    }\n\n    if (typeof cExpr !== \"string\") {\n      throw new TypeError(\"First argument of app.setTimeOut must be a string\");\n    }\n    if (typeof nMilliseconds !== \"number\") {","sourceCodeStart":600,"sourceCodeEnd":636,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/scripting_api/app.js#L600-L636","documentation":"app.setInterval's second argument is the repeat interval in milliseconds and must be a number. PDF.js accepts the object form {nMilliseconds} but, after unwrapping, requires a numeric value; otherwise it throws TypeError. This prevents non-numeric delays reaching the host scheduler.","triggerScenarios":"Calling app.setInterval('myFunc()', '1000') with a string delay, or object form {cExpr:'myFunc()', nMilliseconds:'1000'}. The check at src/scripting_api/app.js:618 fails typeof nMilliseconds !== 'number'.","commonSituations":"Delay read from a form field or config string and passed uncoerced; default 0 overridden by a non-numeric value; Acrobat JS docs accepting string numbers but PDF.js being stricter.","solutions":["Pass the delay as a number literal: app.setInterval('myFunc()', 1000).","Coerce values from untrusted sources: Number(field.value) before calling.","In object form, ensure nMilliseconds is a number, not a string."],"exampleFix":"// before\napp.setInterval('myFunc()', field.value); // string from form\n// after\napp.setInterval('myFunc()', Number(field.value));","handlingStrategy":"type-guard","validationCode":"// Coerce numeric delay before calling app.setInterval.\nfunction scheduleInterval(app, cExpr, nMilliseconds = 0) {\n  const ms = Number(nMilliseconds);\n  if (!Number.isFinite(ms)) throw new TypeError('nMilliseconds must be a finite number');\n  return app.setInterval(cExpr, ms);\n}","typeGuard":"const isFiniteNumber = (v) => typeof v === 'number' && Number.isFinite(v);","tryCatchPattern":"try { app.setInterval('fn()', maybeMs); }\ncatch (e) {\n  if (!(e instanceof TypeError && /Second argument of app\\.setInterval/.test(e.message))) throw e;\n  app.setInterval('fn()', 0); // safe default\n}","preventionTips":["Always pass the delay as a numeric literal.","Coerce form-field/config values with Number() and check Number.isFinite.","In object form, set nMilliseconds as a number."],"tags":["scripting-api","type-validation","setinterval","numeric-coercion"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}