{"record":{"id":"9a1b8c9dd6be6a35","repo":"openclaw/openclaw","slug":"android-release-builds-require-a-readable-git-chec","errorCode":null,"errorMessage":"Android release builds require a readable Git checkout","messagePattern":"Android release builds require a readable Git checkout","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"apps/android/scripts/build-release-artifacts.ts","lineNumber":148,"sourceCode":"    runGit?: (args: string[], cwd: string) => string;\n  } = {},\n): void {\n  const cwd = options.rootDir ?? rootDir;\n  const runGit =\n    options.runGit ??\n    ((args: string[], gitCwd: string) =>\n      execFileSync(\"git\", args, {\n        cwd: gitCwd,\n        encoding: \"utf8\",\n        stdio: [\"ignore\", \"pipe\", \"ignore\"],\n      }));\n  let head: string;\n  let status: string;\n  try {\n    head = normalizeFullGitCommit(runGit([\"rev-parse\", \"HEAD\"], cwd));\n    status = runGit([\"status\", \"--porcelain\", \"--untracked-files=all\"], cwd).trim();\n  } catch {\n    throw new Error(\"Android release builds require a readable Git checkout\");\n  }\n  if (head !== expectedCommit) {\n    throw new Error(`Android release commit mismatch: metadata ${expectedCommit}, checkout ${head}`);\n  }\n  if (status) {\n    throw new Error(\"Android release builds require a clean Git checkout\");\n  }\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n  let artifact: CliOptions[\"artifact\"] = \"all\";\n  let dryRun = false;\n  let verifyApk: string | undefined;\n\n  for (let index = 0; index < argv.length; index += 1) {\n    const arg = argv[index];\n    switch (arg) {\n      case \"--artifact\": {","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/openclaw/openclaw/blob/01804a75319da4b69c9ab98ceaa30477e22b8c0b/apps/android/scripts/build-release-artifacts.ts#L130-L166","documentation":"Thrown by the pre-build git verification block when either `git rev-parse HEAD` or `git status --porcelain --untracked-files=all` against the working directory raises. Unlike error [4] (which only reads SHA), this gate also requires `git status` to succeed because the release must be reproducible from a clean tree. The release build refuses to start without a readable, inspectable checkout.","triggerScenarios":"Running the build inside a container where git is missing at verification time even though metadata was resolved earlier; rootDir/file ownership mismatch making git refuse to read the index; a checkout that lost its .git between metadata resolution and verification.","commonSituations":"Cross-stage Docker builds where an earlier stage computed metadata but a later stage lacks git; permission changes (chown) that break git's safe.directory check; running as a different user than the one that cloned.","solutions":["Run the whole release in one environment that has git and owns the checkout.","Add the checkout owner with `git config --global --add safe.directory <path>`.","Do not split metadata resolution and build verification across containers.","Verify with `git -C <rootDir> rev-parse HEAD && git -C <rootDir> status --porcelain` before invoking."],"exampleFix":"// before\nsudo -u release-user bun build-release-artifacts.ts  # git refuses (dubious ownership)\n// after\ngit config --global --add safe.directory \"$PWD\"\nbun apps/android/scripts/build-release-artifacts.ts","handlingStrategy":"validation","validationCode":"function assertReadableGit(rootDir: string): void {\n  for (const args of [['rev-parse', 'HEAD'], ['status', '--porcelain', '--untracked-files=all']]) {\n    execFileSync('git', args, { cwd: rootDir, stdio: 'ignore', encoding: 'utf8' });\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  head = runGit(['rev-parse', 'HEAD'], cwd);\n  status = runGit(['status', '--porcelain', '--untracked-files=all'], cwd);\n} catch {\n  throw new Error('Android release builds require a readable Git checkout');\n}","preventionTips":["Run the entire release in one environment that owns the checkout.","If running as a different user, run `git config --global --add safe.directory <path>`.","Do not split metadata resolution and build verification across containers."],"tags":["android","release","git","verification","filesystem"],"backgroundTag":null,"analyzedSha":"01804a75319da4b69c9ab98ceaa30477e22b8c0b","analyzedAt":"2026-08-12T04:37:58.197Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}