Skip to content

Rollback by deployment_id is refused (409) for any kept release that loaded a package: component #3748

Open

Description

@Ethan-Arrowood

Bug Summary

Activating a kept release by deployment_id fails with HTTP 409 if that release loaded anything through a package: entry. Every project from npm create harper has one (@harperfast/schema-codegen), so v5.3 rollback, including Studio's Roll back to this release, does not work for the default project shape.

Steps to Reproduce

On a v5.3.0+ node (I used Harper Pro 5.3.4 from npm):

npm create harper@latest my-api -- --template vanilla
cd my-api
harper deploy project=my-app restart=true   # release A
harper deploy project=my-app restart=true   # release B; A is kept
harper deploy project=my-app deployment_id=<A> restart=true

Expected Behavior

Release A is activated and serves again.

Actual Behavior

The last deploy fails with 409:

Cannot activate my-app: <release A>/node_modules/@harperfast/schema-codegen/node_modules/harper links outside the build to <harper install>, so the bytes activated later would not be the bytes this build certified

Cause

Confirmed on origin/main @ 984dcc838, and the same code is in v5.3.0 and v5.3.4.

  • components/componentLoader.ts:972 calls symlinkHarperModule(componentDirectory) on every non-root component load. A package: entry in an application's config.yaml is loaded through loadComponent(componentPath, ..., { isRoot: false }) (:1054), with componentPath = <app>/node_modules/<package>. So while release A was live, the loader wrote <app>/node_modules/@harperfast/schema-codegen/node_modules/harper, pointing at the running install.
  • assertOwnedArtifactTree (components/Application.ts:1568) exempts harper/harperdb links only directly under the candidate's own node_modules (dirPath === loaderOwnedDir, :1592). That is deliberate: the comment says matching the name at any depth would let dep/node_modules/harper point anywhere. activateStagedArtifact re-runs the check with 'activate' (:5325), so the link the loader itself wrote makes release A impossible to activate.

I only exercised activation. validateCandidate runs before the stage-time check (:5183), so staging the same project for delayed activation may hit this too. I haven't tested that.

Suggested fix

Either:

  • extend the exemption to the node_modules/harper and node_modules/harperdb of each directory the loader loads as a component (the package: entries), and only when the link resolves to the running install, so a dependency's link to anywhere else is still refused; or
  • remove loader-owned links before a release is kept, and let the loader recreate them on load.

Workaround

Redeploy the previous release from its commit, or pass its version as package, as before v5.3.0. HarperFast/documentation#671 documents this in Learn > Administration > Safe deployments and rollback.

Platform

macOS 26.6.2, Node v24.19.0, @harperfast/harper-pro@5.3.4 from npm.

sent with Claude Opus 5.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    Priority

    P1

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions