{"record":{"id":"d36aae7be6311b90","repo":"can1357/oh-my-pi","slug":"argv-0-printed-no-url-on-stdout","errorCode":null,"errorMessage":"${argv[0]} printed no URL on stdout","messagePattern":"(.+?) printed no URL on stdout","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders.ts","lineNumber":112,"sourceCode":"\t\t\t\t\targ.replaceAll(\"{file}\", file).replaceAll(\"{mime}\", mimeType).replaceAll(\"{ext}\", extension),\n\t\t\t\t);\n\t\t\t\tconst cwd = getProjectDir();\n\t\t\t\tif (!directoryIsEnterableSync(cwd)) {\n\t\t\t\t\tthrow new Error(`Project directory is not accessible: ${cwd}`);\n\t\t\t\t}\n\t\t\t\tconst proc = Bun.spawn(argv, { stdin: \"ignore\", stdout: \"pipe\", stderr: \"pipe\", cwd });\n\t\t\t\tconst timeout = setTimeout(() => proc.kill(), UPLOAD_TIMEOUT_MS);\n\t\t\t\tconst [stdout, stderr, exitCode] = await Promise.all([\n\t\t\t\t\tnew Response(proc.stdout as ReadableStream<Uint8Array>).text(),\n\t\t\t\t\tnew Response(proc.stderr as ReadableStream<Uint8Array>).text(),\n\t\t\t\t\tproc.exited,\n\t\t\t\t]);\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tif (exitCode !== 0) {\n\t\t\t\t\tthrow new Error(`${argv[0]} exited with code ${exitCode}: ${stderr.trim().slice(-300)}`);\n\t\t\t\t}\n\t\t\t\tconst url = extractUploadUrl(stdout);\n\t\t\t\tif (!url) throw new Error(`${argv[0]} printed no URL on stdout`);\n\t\t\t\treturn { url, destination: \"command\", bytes: bytes.byteLength };\n\t\t\t} finally {\n\t\t\t\tawait fs.rm(file, { force: true });\n\t\t\t}\n\t\t},\n\t};\n}\n\n/**\n * Resolve one registry destination to its built-in uploader.\n *\n * Serving destinations deliberately return `null`; the broker selects those\n * through its separate serve-kind predicate. Registry entries known to be\n * unusable, and active entries without an implementation, fail explicitly\n * before an upload can issue a network request.\n */\nexport function createConfiguredUploader(\n\tdestination: BlobDestinationId,","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders.ts#L94-L130","documentation":"After the upload command exits successfully (code 0), extractUploadUrl() scans stdout for a URL. If none is found, the uploader cannot produce a BlobPublication and throws this error naming the program. The command must print the resulting upload URL to stdout.","triggerScenarios":"The configured command exits 0 but prints nothing to stdout, prints only human-readable text/progress to stdout, sends the URL to stderr or a file, or prints a URL format extractUploadUrl does not recognize (e.g. URL embedded in ANSI-colored or JSON output not matched by the extractor).","commonSituations":"Using a tool that prints results to stderr by default; wrapping the tool in a script that swallows stdout; a tool whose success output is a JSON blob the regex doesn't match; redirecting URL output to a file in the command template.","solutions":["Make the command print the URL to stdout, e.g. append `| tail -1` or use the tool's quiet/url-only mode","Check whether the tool prints the URL to stderr and redirect: `tool {file} 2>&1`","Ensure the output contains a plain http(s) URL the extractor can find (avoid ANSI colors: add --no-color or pipe through sed)","Test locally: run the command and confirm a bare URL appears on stdout"],"exampleFix":"// before\n\"urls\": { \"command\": \"imgur-uploader {file} --json\" }\n// after\n\"urls\": { \"command\": \"imgur-uploader {file} --json | jq -r .link\" }","handlingStrategy":"validation","validationCode":"// verify the tool prints a bare URL on stdout before configuring:\nconst out = Bun.spawnSync([\"your-uploader\", \"/tmp/test.png\"], { stdout: \"pipe\" }).stdout.toString();\nif (!/https?:\\/\\/\\S+/.test(out)) throw new Error(\"uploader must print an http(s) URL to stdout\");","typeGuard":null,"tryCatchPattern":"try {\n\tawait uploader.upload(req);\n} catch (err) {\n\tif (err instanceof Error && err.message.includes(\"printed no URL on stdout\")) {\n\t\t// check where the tool emits the URL and normalize the command (jq/sed, 2>&1)\n\t}\n\tthrow err;\n}","preventionTips":["Ensure the tool prints a plain http(s) URL as stdout output","Strip ANSI colors (--no-color) or pipe through jq/sed to extract the URL","Redirect URL-bearing stderr into stdout if the tool logs there","Verify extraction with a real run before saving the command to config"],"tags":["command-uploader","stdout","url-extraction","subprocess"],"backgroundTag":"missing-url-in-output","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}