{"record":{"id":"ad713f41c3ba438f","repo":"mozilla/pdf.js","slug":"first-argument-of-app-settimeout-must-be-a-string","errorCode":null,"errorMessage":"First argument of app.setTimeOut must be a string","messagePattern":"First argument of app\\.setTimeOut must be a string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/scripting_api/app.js","lineNumber":634,"sourceCode":"    }\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\") {\n      throw new TypeError(\"Second argument of app.setTimeOut must be a number\");\n    }\n    const callbackId = this._registerTimeoutCallback(cExpr);\n    this._externalCall(\"setTimeout\", [callbackId, nMilliseconds]);\n    return this._registerTimeout(callbackId, false);\n  }\n\n  trustedFunction() {\n    /* Not implemented */\n  }\n\n  trustPropagatorFunction() {\n    /* Not implemented */\n  }\n}\n","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/scripting_api/app.js#L616-L652","documentation":"app.setTimeOut schedules a one-shot PDF-JavaScript expression after nMilliseconds. PDF.js requires the first argument to be a code string (or object {cExpr, nMilliseconds}); if cExpr is not a string after unwrapping, a TypeError is thrown. This mirrors Acrobat JS semantics and protects the sandbox.","triggerScenarios":"Calling app.setTimeOut(myFunc, 500) where myFunc is a function reference, or object form {cExpr: 42}; the check at src/scripting_api/app.js:634 fails typeof cExpr !== 'string'.","commonSituations":"Authors transferring window.setTimeout(fn, ms) habits to the Acrobat API; passing undefined because the expression was thought optional; object-form missing cExpr.","solutions":["Pass the expression as a string: app.setTimeOut('myFunc()', 500).","If using object form, include a string cExpr: {cExpr:'myFunc()', nMilliseconds:500}.","Avoid passing function references; the Acrobat JS scheduler evaluates code strings."],"exampleFix":"// before\napp.setTimeOut(() => { doX(); }, 500);\n// after\napp.setTimeOut('doX()', 500);","handlingStrategy":"type-guard","validationCode":"// Validate cExpr is a string before calling app.setTimeOut.\nfunction scheduleTimeout(app, cExpr, nMilliseconds = 0) {\n  if (typeof cExpr !== 'string' || cExpr.length === 0) {\n    throw new TypeError('cExpr must be a non-empty string');\n  }\n  return app.setTimeOut(cExpr, nMilliseconds);\n}","typeGuard":"const isCodeString = (v) => typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":"try { app.setTimeOut(maybeExpr, 500); }\ncatch (e) {\n  if (!(e instanceof TypeError && /First argument of app\\.setTimeOut/.test(e.message))) throw e;\n  // fall back to no-op or host scheduler\n}","preventionTips":["Acrobat JS app.setTimeOut takes a code string, never a function reference.","Validate input type before calling when values originate from user/form input.","Prefer the object form {cExpr, nMilliseconds} only when cExpr is a string."],"tags":["scripting-api","type-validation","settimeout","acrobat-js"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}