{"record":{"id":"0216ce2ce564a511","repo":"iflytek/astron-agent","slug":"errmsg-dynamic-logged-as-open-errmsg-isusernotallow","errorCode":null,"errorMessage":"errMsg (dynamic; logged as '录音open失败：'+errMsg+',isUserNotAllow:'+isUserNotAllow)","messagePattern":"errMsg \\(dynamic; logged as '录音open失败：'\\+errMsg\\+',isUserNotAllow:'\\+isUserNotAllow\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"console/frontend/src/utils/record/recorder-core.js","lineNumber":754,"sourceCode":"        return this;\n      } else {\n        return Recorder;\n      }\n    },\n\n    //打开录音资源True(),False(msg,isUserNotAllow)，需要调用close。注意：此方法是异步的；一般使用时打开，用完立即关闭；可重复调用，可用来测试是否能录音\n    open: function (True, False) {\n      var This = this,\n        streamStore = This._streamStore();\n      True = True || NOOP;\n      var failCall = function (errMsg, isUserNotAllow) {\n        isUserNotAllow = !!isUserNotAllow;\n        This.CLog(\n          '录音open失败：' + errMsg + ',isUserNotAllow:' + isUserNotAllow,\n          1\n        );\n        False && False(errMsg, isUserNotAllow);\n        throw new Error(errMsg);\n      };\n\n      var ok = function () {\n        This.CLog('open ok id:' + This.id);\n        True();\n\n        This._SO = 0; //解除stop对open中的start调用的阻止\n      };\n\n      //同步锁\n      var Lock = streamStore.Sync;\n      var lockOpen = ++Lock.O,\n        lockClose = Lock.C;\n      This._O = This._O_ = lockOpen; //记住当前的open，如果变化了要阻止close，这里假定了新对象已取代当前对象并且不再使用\n      This._SO = This._S; //记住open过程中的stop，中途任何stop调用后都不能继续open中的start\n      var lockFail = function () {\n        //允许多次open，但不允许任何一次close，或者自身已经调用了关闭\n        if (lockClose != Lock.C || !This._O) {","sourceCodeStart":736,"sourceCodeEnd":772,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/frontend/src/utils/record/recorder-core.js#L736-L772","documentation":"recorder-core's open() failure callback (failCall). When opening the recording resource fails, it logs '录音open失败：'+errMsg+',isUserNotAllow:'+isUserNotAllow, invokes the caller's False callback, and throws new Error(errMsg). errMsg is dynamic — permission denial, environment check failure, or the open being cancelled/interrupted by a close call.","triggerScenarios":"Recorder.open() failing for any reason: getUserMedia rejection (NotAllowedError → isUserNotAllow=true), NotReadableError/no device, envCheck returning a message ('不能录音：...'), or the library's sync lock detecting close-during-open ('open被取消'/'open被中断').","commonSituations":"Mic permission blocked; hardware mic in use by Zoom/Teams; http origin; rapid open→close toggling in UI causing the lock-cancel path to fire.","solutions":["Always pass a False callback to open() and handle (errMsg, isUserNotAllow) there; treat isUserNotAllow as a permissions UX problem","Serve over HTTPS and verify Recorder.Support() before calling open","Serialize open/close calls so close never lands mid-open (avoids open被取消/open被中断)","Catch the thrown error around open() to keep the UI stable"],"exampleFix":"// before\nrec.open(() => rec.start()); // no False handler; error thrown uncaught\n// after\nrec.open(\n  () => rec.start(),\n  (errMsg, isUserNotAllow) => {\n    console.error('open failed:', errMsg, 'userDenied:', isUserNotAllow);\n    showMicHelp(isUserNotAllow);\n  }\n);","handlingStrategy":"try-catch","validationCode":"if (!Recorder.Support()) { showUnsupported(); return; }","typeGuard":"function openSafe(rec, onOk) {\n  return new Promise((resolve, reject) => rec.open(resolve, (m, u) => reject({ m, u })));\n}","tryCatchPattern":"rec.open(\n  () => rec.start(),\n  (errMsg, isUserNotAllow) => {\n    if (isUserNotAllow) showPermissionHelp();\n    else console.error('录音open失败:', errMsg);\n  }\n);","preventionTips":["Always supply both True and False callbacks to open()","Avoid calling close() while open() is pending","Run on HTTPS and verify browser support first"],"tags":["audio","microphone","permissions","recorder-core"],"backgroundTag":"permission-denied","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}