Three GitHub Pages gotchas, conquered
Three failed deploys in a row before the splash actually shipped. None of them were our code; all of them were GitHub Pages onboarding friction nobody warns you about. We documented every one — what failed, what fixed it, and the canonical workflow shape that survives them — so the next Lossless repo can pay this setup tax in minutes instead of an hour.
Why Care?
GitHub Pages markets itself as "free static hosting from your repo." The page that explains how to use it makes it look like four clicks and you're done. The reality, on a brand-new repo, is that there are at least three independent first-time gotchas — each producing a different error message that looks like a different problem but isn't.
If you've ever stared at a red ❌ next to "Deploy splash to GitHub Pages" and wondered whether the workflow was wrong, the repo was wrong, or you yourself were wrong, this entry is for you. None of those. It's GitHub.
This is also the entry that turns the gotchas into a playbook the next Lossless repo gets for free. Captured at astro-knots/references/playbooks/github-pages-deploy.md in the agent skill tree.
What's New?
One-line workflow fix landed that makes the workflow self-bootstrap:
enablement: trueonactions/configure-pages@v5. Without it, the very first run on a brand-new repo fails withGet Pages site failed ... Not Found.Build runtime bumped from Node 20 to Node 22 ahead of GitHub's September 2026 deprecation cutoff. Removes a recurring deprecation warning on every run.
Three setup-time gotchas documented as a playbook in the
astro-knotsskill, with order-of-operations and the exact UI paths to fix each.Splash is queued for its first successful deploy at
lossless-group.github.io/content-farm/. Failed three times before we got the configuration right; the latest run, triggered after all three were addressed, should succeed.
The three gotchas (in the order they bite)
Gotcha 1: First-run 404 from actions/configure-pages
The error:
Error: Get Pages site failed. Please verify that the repository has Pages
enabled and configured to build using GitHub Actions, or consider exploring
the `enablement` parameter for this action.
Error: Not Found - https://docs.github.com/rest/pages/pages#get-a-apiname-pages-site
Error: HttpError: Not FoundThe cause: actions/configure-pages queries GET /repos/{owner}/{repo}/pages to find the existing Pages site. On a brand-new repo, that resource doesn't exist yet. The 404 propagates as a hard failure.
The fix — one line:
- name: Configure Pages
uses: actions/configure-pages@v5
+ with:
+ # Auto-enable Pages on first run so the workflow bootstraps itself
+ # even when "Get Pages site" returns 404 the very first time.
+ enablement: trueenablement: true makes the action POST to provision the Pages site if the GET 404s, using the pages: write permission already declared on the workflow. On second and subsequent runs, it just uses the existing site — no harm.
This was the original ticket-zero gotcha. Once enablement: true was in, the build job started succeeding. Then the deploy job started failing — for an entirely different reason.
Gotcha 2: Branch not allowed to deploy
The error:
Branch "main" is not allowed to deploy to github-pages due to environment
protection rules.
The deployment was rejected or didn't satisfy other protection rules.The cause: GitHub auto-creates a github-pages environment the first time a Pages workflow runs. That environment has a default deployment-branch rule that limits deploys to the repository's default branch. content-farm's default branch was still master from when the repo was initialized; we'd just created main to match the dev → main → master tier model and were deploying from it. The environment didn't agree.
Two ways to fix it. Both work.
(A) Allow main in the environment's deployment-branch policy. UI path: Settings → Environments → github-pages → "Deployment branches and tags" → "Add deployment branch or tag rule" → enter main → Add. Or via the API:
gh api -X POST repos/lossless-group/content-farm/environments/github-pages/deployment-branch-policies \
-f name=main -f type=branchAfter this fix, the branch_policies for the env contained both:
{
"total_count": 2,
"branch_policies": [
{ "id": 48640893, "name": "main", "type": "branch" },
{ "id": 48640114, "name": "master", "type": "branch" }
]
}(B) Change the repo's default branch to main. Settings → Branches → switch default. More invasive — affects PR base branches, branch protection rules, contributor expectations everywhere. We took option B for content-farm because aligning with the tier model was overdue anyway. For most other repos in the family, option A is the lighter touch.
After this fix, the rejection message should disappear on subsequent runs.
Gotcha 3: Source still set to "Deploy from a branch"
The error: No error per se — but the workflow runs to completion, and lossless-group.github.io/content-farm/ either 404s or shows a Jekyll-built blank page. Settings → Pages shows a Branch dropdown with master selected, a Folder dropdown with / (root) or /docs, and a polite suggestion to "add a Jekyll theme."
The cause: Pages has two completely different deployment modes. Both are reached from Settings → Pages, but they use different infrastructure:
| Mode | What it does |
| Deploy from a branch | Treats the chosen folder of the chosen branch as a Jekyll site. Builds and serves it. |
| GitHub Actions | Receives an artifact from a workflow's actions/upload-pages-artifact step and serves it. |
If Source is set to "Deploy from a branch," your workflow's deploy-pages step has nothing to deploy to — Pages is busy doing its own Jekyll build and ignoring your artifact upload entirely.
The fix: Settings → Pages → "Build and deployment" → Source dropdown → change from "Deploy from a branch" to "GitHub Actions". The Branch and Folder pickers vanish; the Jekyll suggestion vanishes; a workflow-status panel takes their place.
This one is the sneakiest of the three because the legacy-mode UI sits exactly where you'd expect the Actions-mode UI to sit. Easy to miss the dropdown.
The Node 20 deprecation, while we were here
GitHub Actions runners are in the middle of deprecating Node 20. Every workflow run produced this warning:
Node.js 20 actions are deprecated. The following actions are running on
Node.js 20 and may not work as expected: actions/checkout@v4,
actions/configure-pages@v5, actions/setup-node@v4, actions/upload-artifact@v4,
pnpm/action-setup@v4. Actions will be forced to run with Node.js 24 by default
starting June 2nd, 2026. Node.js 20 will be removed from the runner on
September 16th, 2026.Two layers there:
The actions themselves (
checkout,configure-pages, etc.) ship Node 20 internally. Resolving that requires the action maintainers to publish updated tags. Out of our hands; nothing to fix locally.The Node version our build uses (the
node-version: 20in oursetup-nodestep). That one we control. Bumped to22LTS:
- name: Setup Node
uses: actions/setup-node@v4
with:
- node-version: 20
+ node-version: 22
cache: pnpm
cache-dependency-path: splash/pnpm-lock.yamlNode 22 is the current LTS as of this push. Node 24 is the next LTS but isn't out long enough yet to be the default everywhere.
The canonical workflow, post-fixes
The full state of .github/workflows/pages.yml after this round, for reference and for any future Lossless repo that wants the recipe:
name: Deploy splash to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: splash
steps:
- uses: actions/checkout@v4
with:
submodules: recursive # crucial when content rolls up via the Content API
fetch-depth: 1
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 22 # bumped from 20 ahead of deprecation
cache: pnpm
cache-dependency-path: splash/pnpm-lock.yaml
- run: pnpm install --frozen-lockfile=false
- run: pnpm build
- uses: actions/configure-pages@v5
with:
enablement: true # self-bootstrap on first run
- uses: actions/upload-pages-artifact@v3
with:
path: splash/dist
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4Three things to notice if you're copying this:
defaults.run.working-directory: splash— required because the Astro app lives at a subpath. Thecache-dependency-pathand the artifactpathuse the absolute-from-repo-root path; everything else is relative tosplash/.enablement: trueonconfigure-pages— Gotcha 1 fix, in the workflow itself.submodules: recursiveon checkout — needed even before the roll-up loader lands, because the splash's content collections currently glob into../context-vand that pulls in spec/plan files that may reference submodule context.
What got captured outside the repo
The three gotchas above are now a playbook in the astro-knots skill at references/playbooks/github-pages-deploy.md. The playbook covers:
The full canonical workflow shape (above)
The
astro.config.mjsbasesetting that has to match the repo pathEach gotcha with symptom, cause, fix
A 6-step setup checklist in the order each gotcha bites
Verification steps
Cross-references to the new-site-setup playbook (Vercel default) and the content-rollup reference
Linked from the astro-knots SKILL.md in two places — the "Initiating a new Astro-Knots project" section and the "See also" list — so it's reachable from any Astro Knots task.
The honest middle
The first three workflow runs (commit hashes 61dfe40, 37fba2c, 9d504cc) all failed on main. The screenshot of the Actions tab at one point looked like:
3 workflow runs
❌ fix(pages-workflow): self-bootstrap GitHub Pages on first run main
❌ seed(roll-up): bump submodule pointers... main
❌ ship(splash): launch the content-farm GitHub Pages splash... mainEach failure was a different one of the three gotchas. The first two failed at Gotcha 1 (no enablement: true). The third pushed the enablement: true fix and got past it, then failed at Gotcha 2 (env protection on main). After fixing the default branch and re-triggering manually via gh workflow run, that finally got past Gotcha 2 — and then we noticed Gotcha 3 (Source on "Deploy from a branch") in the Pages settings, which had been sitting there silently the whole time. Flipped it. The most-recent run as of this entry's push is queued at https://github.com/lossless-group/content-farm/actions/runs/25356485378 and should succeed.
If you're feeling demoralized, three failed deploys is cheap compared to writing this playbook before doing the work. The playbook costs nothing to read and saves the next person from doing the live debug.
What's next
Watch the latest run. If it succeeds, the splash goes live. If it fails again, the env policy may need to be deleted and recreated (the API said both branches were allowed but the rule still blocked deploys at one point — flagged as the only remaining unknown).
Roll-up loader still next on the spec. Three gotchas of GitHub Pages onboarding doesn't change Phase 2 priorities.
Workflow re-use. When the next Lossless repo wants its splash, this
pages.ymlis the template. Copy verbatim, changesplashto the relevant subpath, change[main]to the desired publication branch.
