{"record":{"id":"4c2d58a14bded9da","repo":"paperclipai/paperclip","slug":"input-label-sync-wrote-invalid-result-json-e","errorCode":null,"errorMessage":"${input.label} sync wrote invalid result JSON: ${error instanceof Error ? error.message : String(error)}","messagePattern":"(.+?) sync wrote invalid result JSON: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/adapter-utils/src/sandbox-callback-bridge.ts","lineNumber":970,"sourceCode":"      \"    exit 1\",\n      \"  fi\",\n      \"else\",\n      `  echo ${shellQuote(`${input.label} sha verify skipped: no sha256sum/shasum on remote.`)} >&2`,\n      \"fi\",\n      \"mv \\\"$remote_partial\\\" \\\"$remote_path\\\"\",\n      \"printf '{\\\"uploaded\\\":true}\\\\n'\",\n    ].join(\"\\n\"),\n    timeoutMs,\n    shellCommand,\n    base64Body,\n  );\n  requireSuccessfulResult(input.action, syncResult);\n\n  let uploaded = false;\n  try {\n    uploaded = JSON.parse(syncResult.stdout.trim())?.uploaded === true;\n  } catch (error) {\n    throw new Error(\n      `${input.label} sync wrote invalid result JSON: ${error instanceof Error ? error.message : String(error)}`,\n    );\n  }\n\n  return { uploaded, sha256 };\n}\n\nexport async function syncSandboxCallbackBridgeEntrypoint(input: {\n  runner: CommandManagedRuntimeRunner;\n  remoteCwd: string;\n  assetRemoteDir: string;\n  bridgeAsset: SandboxCallbackBridgeAsset;\n  timeoutMs?: number | null;\n  shellCommand?: \"bash\" | \"sh\" | null;\n}): Promise<{ remoteEntrypoint: string; sha256: string; uploaded: boolean }> {\n  const remoteEntrypoint = path.posix.join(input.assetRemoteDir, SANDBOX_CALLBACK_BRIDGE_ENTRYPOINT);\n  const entrypointSource = await fs.readFile(input.bridgeAsset.entrypoint, \"utf8\");\n  const { uploaded, sha256 } = await syncRemoteTextFileWithHashSkip({","sourceCodeStart":952,"sourceCodeEnd":988,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapter-utils/src/sandbox-callback-bridge.ts#L952-L988","documentation":"Thrown by syncRemoteTextFileWithHashSkip after the remote upload script completed successfully (requireSuccessfulResult passed, exit code 0) but stdout could not be parsed as JSON with an uploaded field. The script prints {\"uploaded\":true} after a fresh upload, {\"uploaded\":false} after a sha256 short-circuit skip; any other stdout breaks JSON.parse and surfaces as this error with the parse failure attached.","triggerScenarios":"Remote shell prints a banner, trace, or warning to stdout before the printf; sha256sum or shasum on the remote emits output that escapes the script's redirection discipline; or a partial run left stdout truncated. The parse at sandbox-callback-bridge.ts:968 throws, which is wrapped with input.label (e.g. \"Sandbox callback bridge entrypoint\") for context.","commonSituations":"Same family as 337: SSH MOTD, .bashrc echoes, set -x shell tracing, or PAM modules writing to stdout. Specific to this code path: missing hash tools on minimal remotes (Alpine/scratch) trigger the sha-verify-skipped branch but still print the expected JSON, so that path alone does not cause this error; the cause is stdout pollution or a truncated shell result.","solutions":["Silence non-interactive shell noise on the remote: run bash --noprofile --norc -c '...' and remove stdout-echoing statements from .bashrc/.profile.","Use the bridge's shellCommand option to force a clean shell (\"bash\" with --noprofile --norc, or \"sh\" for minimal remotes).","Disable ssh MOTD/banner output for the runtime user (sshd config: PrintMotd no, Banner none; remove /etc/motd echoes).","When debugging, log syncResult.stdout verbatim before JSON.parse — the raw text reveals the polluting line, which the wrapped error does not include."],"exampleFix":"// before: remote /etc/profile echoes a welcome line to stdout\n// echo \"Welcome to $HOSTNAME\"  # delete or redirect to stderr\n\n// after: pass a clean non-interactive shell to the bridge\nsyncSandboxCallbackBridgeEntrypoint({\n  runner, remoteCwd, assetRemoteDir, bridgeAsset,\n  shellCommand: \"bash\",\n});\n// and ensure the runtime user's startup files are silent non-interactively","handlingStrategy":"validation","validationCode":"async function preflightSyncShellIsSilent(input: { runner: CommandManagedRuntimeRunner; remoteCwd: string }): Promise<void> {\n  const result = await runShell(input.runner, input.remoteCwd, 'printf \\'{\"uploaded\":true}\\\\n\\'', 5000, \"bash\");\n  try {\n    if (JSON.parse(result.stdout.trim())?.uploaded !== true) {\n      throw new Error(`Unexpected stdout: ${result.stdout}`);\n    }\n  } catch (error) {\n    throw new Error(`Remote sync shell pollutes stdout; disable MOTD/.bashrc echoes: ${String(error)}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await syncSandboxCallbackBridgeEntrypoint(input);\n} catch (error) {\n  if (error instanceof Error && /sync wrote invalid result JSON/.test(error.message)) {\n    throw new BridgeError(\"Sync remote shell wrote non-JSON to stdout. Suppress MOTD/.bashrc echoes or switch to bash --noprofile --norc.\", { cause: error });\n  }\n  throw error;\n}","preventionTips":["Pass shellCommand: \"bash\" (with --noprofile --norc startup) when constructing the sync input.","Silence remote /etc/profile, /etc/motd, and sshd Banner output for the runtime user.","Guard ~/.bashrc to skip non-interactive sessions.","Log syncResult.stdout verbatim during debugging — the wrapped error omits the offending line."],"tags":["bridge","remote-runtime","shell","json","callback-bridge","file-sync"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}