{"record":{"id":"9536e31ffea1b419","repo":"Hmbown/CodeWhale","slug":"the-installed-version-could-not-be-read","errorCode":null,"errorMessage":"The installed version could not be read.","messagePattern":"The installed version could not be read\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/app/updates.mjs","lineNumber":133,"sourceCode":"  const child=spawn(process.execPath,[fileURLToPath(import.meta.url),\"--apply\",prepared.bundle,destination,String(process.pid),String(process.ppid)],{detached:true,stdio:[\"ignore\",log,log]});\n  try { await new Promise((resolve,reject)=>{child.once(\"spawn\",resolve);child.once(\"error\",reject);}); child.unref(); }\n  finally { fs.closeSync(log); }\n}\n\nif(process.argv[1]===fileURLToPath(import.meta.url)&&process.argv[2]===\"--apply\") {\n  const [source,destination,owner,launcher]=process.argv.slice(3);\n  let result;\n  try {\n    verifyReleaseBundle(source);\n    process.kill(Number(owner),\"SIGTERM\");\n    for(let i=0;i<100;i++) { try { process.kill(Number(owner),0); } catch { break; } await new Promise(resolve=>setTimeout(resolve,100)); }\n    try { process.kill(Number(owner),0); throw new Error(\"The running helper did not stop; update cancelled.\"); } catch(error) { if(error.code!==\"ESRCH\") throw error; }\n    // LaunchServices must not send Reopen to the retiring menu-bar process.\n    for(let i=0;i<100;i++) { try { process.kill(Number(launcher),0); } catch { break; } await new Promise(resolve=>setTimeout(resolve,100)); }\n    try { process.kill(Number(launcher),0); throw new Error(\"The menu-bar app did not exit; update cancelled.\"); } catch(error) { if(error.code!==\"ESRCH\") throw error; }\n    const receipt=replaceMacBundle(source,destination,{verify:verifyReleaseBundle});\n    const installed=spawnSync(\"/usr/libexec/PlistBuddy\",[\"-c\",\"Print :CFBundleShortVersionString\",path.join(destination,\"Contents\",\"Info.plist\")],{encoding:\"utf8\"});\n    if(installed.status!==0) throw new Error(\"The installed version could not be read.\");\n    console.log(JSON.stringify({version:installed.stdout.trim(),...receipt,installedAt:new Date().toISOString()}));\n    result={ok:true,message:`Updated to ${installed.stdout.trim()}. Choose Allow new sessions when you are ready.`};\n  } catch(error) {\n    console.error(error.message); process.exitCode=1;\n    result={ok:false,message:`The update could not be completed: ${String(error.message).slice(0,600)} Computer sessions remain stopped.`};\n  } finally {\n    // The apply process outlives the menu app. Carry its result into the next\n    // launch so a failed install is visible without hunting for update.log.\n    try {\n      fs.mkdirSync(stateDir(),{recursive:true});\n      const temporary=`${updateResultPath()}.${process.pid}.tmp`;\n      fs.writeFileSync(temporary,JSON.stringify({...result,completedAt:new Date().toISOString()})+\"\\n\",{mode:0o600});\n      fs.renameSync(temporary,updateResultPath());\n    } catch(error) { console.error(`Could not save the update result: ${error.message}`); }\n    if(destination&&fs.existsSync(destination)) spawnSync(\"open\",[\"-g\",\"-a\",destination]);\n  }\n}\n","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/app/updates.mjs#L115-L151","documentation":"After swapping in the new bundle, the install step reads CFBundleShortVersionString from the installed app's Info.plist with PlistBuddy to confirm the installation. A non-zero PlistBuddy status means the version could not be read — the installed bundle is missing its Info.plist, malformed, or PlistBuddy could not run — so the update reports failure rather than claiming success.","triggerScenarios":"replaceMacBundle swapped in a bundle whose Contents/Info.plist is missing or corrupt; PlistBuddy (/usr/libexec/PlistBuddy) is unavailable or blocked on the host; filesystem permissions on the destination make Info.plist unreadable; partial copy/atomic-swap failure left a truncated bundle at the destination.","commonSituations":"Destination volume errors or disk-full during the bundle swap; security software quarantining the newly installed bundle; a corrupted source bundle that passed earlier checks but degraded during replace; non-standard macOS images lacking PlistBuddy.","solutions":["Retry the update — a transient swap failure usually resolves on a second attempt.","Check the destination bundle exists with a readable Contents/Info.plist (plutil -p <dest>/Contents/Info.plist) and that the volume has free space.","Verify /usr/libexec/PlistBuddy exists and is executable; it ships with standard macOS.","Check quarantine/EDR logs for software interfering with the newly installed bundle and re-run after adding an exception."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const {execFileSync} = await import('child_process');\nconst out = execFileSync('/usr/libexec/PlistBuddy', ['-c','Print :CFBundleShortVersionString', `${destination}/Contents/Info.plist`], {encoding:'utf8'});\nif (!out.trim()) throw new Error('installed Info.plist unreadable');","typeGuard":null,"tryCatchPattern":"try { await restartWithUpdate(prepared, destination); } catch (e) { if (/installed version could not be read/.test(e.message)) { /* inspect destination Info.plist / disk / quarantine, then retry */ } else throw e; }","preventionTips":["Ensure the destination volume has free space and no EDR is quarantining new bundles.","Verify the release bundle contains a valid Contents/Info.plist before publishing.","Run updates on standard macOS installs where /usr/libexec/PlistBuddy exists."],"tags":["macos","plist","installation","verification"],"backgroundTag":"subprocess-command-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}