LLumen
← All articles

The CI that couldn't upload: when a token isn't enough

Cover — ci-that-couldnt-upload

The deploy workflow for the CMS apps kept going red. Two problems hid behind one red X, and untangling them is a decent tour of how I debug a pipeline: read the exact failure, then decide whether to fix the path or change it.

Problem one: a prompt with no one to answer it

The job died with exit code 130. That number is the tell — 128 + SIGINT — a process interrupted while waiting. The upload CLI was asking, interactively, Add a comment to the created bundle? and CI has no keyboard. Passing --comment answered the first prompt; a second one (activate the bundle? (Y/n)) needed yes | piped in — with set +o pipefail so the SIGPIPE that kills yes doesn't fail the step. Non-interactive at last.

Problem two: a 404 that wasn't about the URL

Then the upload itself returned 404 on POST /organizations/{org}/app_uploads. A 404 on a write endpoint you can see in the docs is rarely a wrong URL — it's usually the API saying "your credentials can't do this here." And that was it: Contentful's app-bundle hosting needs an OAuth token, not a personal management token. A PAT can read definitions and 404s on uploads.

The decision

I could have stood up an OAuth app with a refresh-token dance in CI. For a portfolio, that's a lot of moving parts to keep a green checkmark. But the apps already live as public demos on Vercel — and the same bundle that serves the demo serves the CMS iframe. So the honest move was to point the deploy workflow at Vercel, where the apps actually run, and keep the Contentful bundle refresh as a local, OAuth-authenticated step.

  • Lost: "CI uploads to Contentful Hosting."

  • Gained: a green, honest pipeline that deploys exactly where the code runs.

A 404 on a write endpoint means "you can't," not "wrong address." And the cheapest fix is often to change where the work happens, not to force the original path.