Hull troubleshooting — common errors and fixes

Look up the error text you saw and follow the fix. If your error isn’t here, open an issue with the exact message and the command that produced it.

Install / upgrade errors

release X already exists

You ran hull install against a name that’s already deployed. Use hull upgrade instead, or hull uninstall first.

secrets "hull.v1.X.v1" already exists

A previous install crashed mid-way and left the storage Secret behind. Delete it and re-install, or mop up with hull purge --force:

kubectl delete secret hull.v1.X.v1 -n <namespace>

release X v1 not found for update

Hull tried to update a revision that isn’t in the storage backend — usually the release Secret was deleted out of band. Confirm with hull list; re-install if needed.

encoded release size N bytes exceeds K8s Secret limit of 1048576 bytes

The rendered manifest plus stored hooks plus audit data exceed the 1 MiB Secret cap. Trim large CRDs out of crds/ and apply them separately, reduce inline value verbosity, or switch to the SQL driver (HULL_DRIVER=sql).

schema validation failed: replicas: 100 exceeds maximum 50

values.schema.json rejected your inputs. Check the named path against the schema — open the package’s values.schema.json (reference) to see the active constraints.

value <key> is required

values.schema.json declares a required field missing from your merged values. Set it (--set key=value or a values file) or relax the schema.

top-level key 'reples' not in schema (did you mean 'replicas'?)

The schema has additionalProperties: false. Fix the typo.

package %q resolves outside allowlisted root

Controller-mode rejection: a HullRelease CR’s spec.package, after symlink resolution, points outside the controller’s --package-root. Fix the CR or extend --package-root.

plan integrity check failed: package or values changed since plan was generated

The package or its values changed between hull plan and hull apply, so the plan’s SHA-256 no longer matches a fresh re-render. Regenerate the plan (hull plan -o new.plan) or revert the package change.

unsupported plan kind X/Y

The plan file’s apiVersion / kind aren’t hull/v1 / Plan — an older plan format or a corrupted file. Regenerate it.

Templating errors

unknown function "eq"

Hull’s expression engine has no eq, ne, lt, gt, and, or, or not functions. (It does have coalesce, default, and ternary.) For comparisons, use $switch or restructure as a discriminator field:

# Won't work:
$if: ${eq values.env "prod"}

# Use $switch instead:
$switch: ${values.env}
$cases:
  prod: { resources: { requests: { cpu: 500m } } }
  staging: { resources: { requests: { cpu: 200m } } }

Math & logic functions, Expressions — Truthy $if.

function "add" failed: expected numeric, got string

You passed a path-shaped argument (${add values.a values.b}). Function arguments are parsed as literals, not paths. Use the pipeline form so the value before | is the path lookup:

${values.a | add 3}          # values.a is the path, 3 is a literal
${values.a | mul values.b}   # ✗ values.b is the literal string "values.b"

For two-path arithmetic, pre-compute the result in values. → Expressions — arguments are literals.

until: range size N exceeds 65536

You’re materialising a list larger than hull’s range cap. Split the work into batches.

repeat: count N exceeds 65536

Same cap — ${"x" | repeat 1000000} is bounded. Reduce the count.

expression: include cycle detected: X

A $include "name" chain re-entered itself. Check _helpers.yaml for a partial that includes itself transitively.

$include chain exceeds depth limit (64)

A non-cyclical chain of distinct partials exceeds 64 levels. Refactor into fewer levels.

partial "name" not found

$include: name referenced a partial that doesn’t exist. Partial names are the top-level YAML keys in _helpers.yaml; check for a typo.

tpl: recursion depth exceeded

${tpl ...} calls nested too deeply. Hull caps tpl recursion at 16 levels.

lookup: cannot map X/Y

The cluster’s discovery doesn’t know that GroupVersionKind — the CRD isn’t installed or the apiVersion is wrong. lookup retries once with a fresh discovery refresh, then fails.

Distribution / registry errors

unauthorized: authentication required

You’re pulling/pushing without credentials. Run hull login <host>. Hull also reads ~/.docker/config.json, so any prior docker login works.

x509: certificate signed by unknown authority

For internal CAs, set HULL_CA_FILE=/path/to/ca.pem. For self-signed dev/test, pass --insecure on hull login or the OCI TLS-skip flags (never in production).

OCI plain-http: credentials suppressed (set HULL_ALLOW_PLAINTEXT_AUTH=1 to override)

Hull refuses to send Basic Auth over plaintext HTTP by default. Fix the registry to use HTTPS, or set HULL_ALLOW_PLAINTEXT_AUTH=1 (or pass --allow-plaintext-auth) for explicit dev-mode opt-in.

redirect to different host "X" blocked (original: "Y")

A repo redirected to a different host. Hull blocks cross-host redirects to prevent credential leakage. Fix the repo’s index or contact its operator.

digest mismatch: expected sha256:abc..., got sha256:def...

The archive on the server doesn’t match its index.yaml-recorded digest — usually someone re-published without regenerating the index. Re-run hull repo index on the publisher side.

archive contains absolute path: /etc/passwd

A tar entry has an absolute path — the archive is hostile or malformed. Hull refuses to extract.

archive contains path traversal: ../../../etc/passwd

A tar entry escapes the destination directory. Hostile or malformed; hull refuses.

A symlink inside the archive points outside the destination. Hull skips all symlinks during extraction; this error means one would have escaped. The archive is hostile.

archive contains more than 65536 entries

Defence against tar bombs that pass per-file and total-size caps with millions of tiny entries. Hostile or malformed.

archive entry "name" size N exceeds 16777216 bytes

A single tar entry declared a size larger than 16 MiB. Hostile.

Signing / verification errors

provenance verification failed: unknown signer (key 0xABCD)

The PGP signature was made by a key not in your keyring. Add the publisher’s public key:

hull keyring add /path/to/signer.pub

provenance verification failed: archive digest sha256:def... does not match signed sha256:abc...

The archive on disk doesn’t match the digest the publisher signed — possible tampering. Re-fetch the original archive.

provenance file (.prov) not found

The repo doesn’t ship a .prov for this artifact. Either drop --verify (insecure) or use a repo that signs.

cosign verify failed: no matching signatures

No cosign signature is attached to that OCI artifact. Use cosign tree <ref> to see what’s there, or drop the cosign verification step.

file ... is not a valid PGP public key

hull keyring add rejected the input because it doesn’t parse as a PGP entity. Confirm with gpg --list-keys that the file is a real public key.

refusing to install key with reserved filename "credentials.json"

You tried to add a keyring file whose name collides with hull’s credential store. Rename the input file.

Cluster / API errors

secrets "hull.v1.X.v1" is forbidden: User "..." cannot create resource "secrets"

Hull writes release records as Secrets in the install namespace, and your kubeconfig user lacks create/get/update/delete secrets there. Grant RBAC, or switch to the ConfigMap driver (HULL_DRIVER=configmap) if Secrets are restricted.

Deployment X/Y rollout failed: ProgressDeadlineExceeded

The Deployment’s progress deadline elapsed before all replicas became Available. Common causes: ImagePullBackOff, CrashLoopBackOff, insufficient quota, failing readiness probe. Run kubectl describe deploy X -n Y for details.

apply: failed to apply X/Y: forbidden: User cannot patch resource

Server-side apply requires patch plus update on the resource. Grant the RBAC.

the server was unable to return a response in the time allotted

The cluster API is overloaded or the operation is timing out. Raise --timeout, or retry at a quieter time. For stuck destructive operations, see hull purge --force.

Workspace / orchestration errors

workspace member "X" depends on unknown member "Y"

hull-workspace.yaml member X lists dependsOn: [Y] but no member Y exists. Fix the spelling or add the member.

workspace dependency cycle: A -> B -> A

Members form a circular dependency. Workspaces can’t install with cycles. Restructure or split into separate workspaces.

Migration

not a Helm chart: Chart.yaml not found in <path>

hull migrate was pointed at a directory without a Chart.yaml. The path must be a Helm chart’s root.

refusing to overwrite non-empty output directory ...; remove it first or set HULL_MIGRATE_FORCE=1

hull migrate won’t silently overwrite a non-empty output directory. Delete it first, or set HULL_MIGRATE_FORCE=1 to acknowledge the data loss.

strict mode: N items require manual review

hull migrate --strict refused to commit because the migrator couldn’t translate everything cleanly. Drop --strict (the items are printed in the conversion report) or hand-edit the chart before re-running.

Storage / drivers

failed to read schema version

The SQL driver couldn’t read its meta table. Check the connection string (HULL_DRIVER_SQL_DSN).

release payload exceeds storage size limit of 1048576 bytes

The memory driver enforces the same 1 MiB cap as the Secret driver to catch oversized releases early in dev/test. Same fix as the Secret error: trim CRDs, switch to SQL, or split the package.

Where next