{"record":{"id":"6dfd1d9f69376943","repo":"siyuan-note/siyuan","slug":"mp3-encoder-is-not-initialized","errorCode":null,"errorMessage":"MP3 encoder is not initialized","messagePattern":"MP3 encoder is not initialized","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/protyle/util/RecordMediaWorker.ts","lineNumber":38,"sourceCode":"    }\n    const buffer = chunk.slice().buffer;\n    workerScope.postMessage({type: \"chunk\", buffer}, [buffer]);\n};\n\nworkerScope.onmessage = (event: MessageEvent<WorkerMessage>) => {\n    try {\n        const message = event.data;\n        if (message.type === \"init\") {\n            encoder = new Mp3Encoder(1, message.sampleRate, message.bitRate);\n            workerScope.postMessage({type: \"ready\"});\n        } else if (message.type === \"encode\") {\n            if (!encoder) {\n                throw new Error(\"MP3 encoder is not initialized\");\n            }\n            postChunk(encoder.encodeBuffer(new Int16Array(message.buffer)));\n        } else if (message.type === \"finish\") {\n            if (!encoder) {\n                throw new Error(\"MP3 encoder is not initialized\");\n            }\n            postChunk(encoder.flush());\n            encoder = undefined;\n            workerScope.postMessage({type: \"finished\"});\n        }\n    } catch (error) {\n        workerScope.postMessage({\n            type: \"error\",\n            message: error instanceof Error ? error.message : String(error),\n        });\n    }\n};\n","sourceCodeStart":20,"sourceCodeEnd":51,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/app/src/protyle/util/RecordMediaWorker.ts#L20-L51","documentation":"Inside the RecordMedia worker script, messages of type \"encode\" or \"finish\" require the MP3 encoder instance to exist. If encoder is undefined (worker not initialized, or an encode/finish arrives after finish already reset it), it throws 'MP3 encoder is not initialized'.","triggerScenarios":"Posting {type: \"encode\"} or {type: \"finish\"} to the recording worker without a prior successful init message, posting encode after finish reset encoder to undefined, or the init message failed silently.","commonSituations":"Recording stop (finish) races with a final queued encode message; worker reused across recordings without re-init; init payload (sample rate/channels) failed causing encoder creation to be skipped.","solutions":["Ensure the worker receives a valid init message (with correct sample rate/channels) before any encode/finish message","Track recording state in the UI and disable encode/finish posts after finish has been sent","Guard the main thread: only post finish once, and await worker ready before sending audio chunks","In the worker, log message.type and encoder state in the catch handler to identify the out-of-order message"],"exampleFix":"// before (main thread)\nworker.postMessage({type: \"finish\"});\nworker.postMessage({type: \"finish\"}); // second call throws\n// after\nlet finished = false;\nconst finish = () => {\n  if (finished) return;\n  finished = true;\n  worker.postMessage({type: \"finish\"});\n};","handlingStrategy":"try-catch","validationCode":"let encoderReady = false;\nworker.addEventListener(\"message\", e => { if (e.data.type === \"ready\") encoderReady = true; });\n// before encode/finish:\nif (!encoderReady) throw new Error(\"worker not initialized\");","typeGuard":"const canPostToRecorderWorker = (state: {initialized: boolean, finished: boolean}): boolean =>\n  state.initialized && !state.finished;","tryCatchPattern":"worker.onerror = e => {\n  if (String(e.message).includes(\"MP3 encoder is not initialized\")) {\n    console.error(\"Recording worker used out of order; re-initializing\");\n    initWorker(worker);\n  }\n};","preventionTips":["Always send init before any encode/finish message","Send finish exactly once per recording session","Reset initialized state after finish and re-init before the next recording","Handle worker error events to detect out-of-order messages early"],"tags":["worker","mp3","recording","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}