Releases and jobs

Releases and jobs. A release is a version of your application that Hangar runs for each of your customers. Each job uses your prepaid credit.

A vendor builds its application once, as a package. Hangar runs a signed, accepted release of the package for each tenant (each customer) of the vendor. Every job ends with the artefacts that the application wrote, and a return. The return is a job certificate. It shows which release ran, the envelope, the pool and every attempt. Anyone can verify the return offline.

TALOS Warrant is the part of Hangar that decides what a job may do. Before a job starts, TALOS Warrant compiles the envelope: the set of limits that the job cannot leave. The envelope comes from what the release asks for and what your policies allow. During the job, TALOS Warrant enforces the envelope. After the job, TALOS Warrant signs the return.

The route, start to end:

  1. You make a release key on your own machine and register it.
  2. You push your image and create a package version from hangar_package.json.
  3. You sign the release and submit it.
  4. TALOS Defence runs the acceptance checks, including a self-test job of the release, and signs its acceptance.
  5. You move a channel, such as stable, to the release.
  6. You start jobs of the release for your tenants, with the Hangar app, the hangar command line or the Python package gethangar.
  7. Each job ends with its artefacts and a signed return.

The reference package hangar_patch_agent in examples/patch-agent follows this route from start to end.

1. The application contract

Your application runs as the entrypoint of the image, in a container on a fresh instance for each attempt. The application reads its inputs and its configuration from fixed paths, and writes its outputs to a fixed folder. The application reports its result with its exit code.

PathWhat is there
/hangar/inputs/<name>The exact bytes of each artefact input, read-only, under the input's name.
/hangar/inputs/values.jsonThe inputs that are not artefacts, as compact JSON with the keys sorted.
/hangar/config/config.jsonThe configuration for the pool and tenant of the job, with the defaults applied, as compact JSON with the keys sorted. Read-only.
/hangar/outputs/Empty and writable. Write each declared output here under its declared name.

The environment:

VariableWhat it holds
HANGAR_RUN_IDThe id of the job.
HANGAR_ATTEMPTThe attempt number, from 1.
HANGAR_RELEASEThe release id, as sha384: and 96 hexadecimal digits.
HANGAR_TENANTThe tenant id, for a job that has a tenant.
HANGAR_INPUTSThe inputs folder, /hangar/inputs.
HANGAR_CONFIGThe configuration folder, /hangar/config.
HANGAR_OUTPUTSThe outputs folder, /hangar/outputs.

Read the folders through the three variables. A local runner, such as the reference package's run_local.py, sets them to temporary folders.

Exit code 0 means that the application finished. Any other code fails the attempt. Hangar still seals and keeps the declared outputs, so you can see what the application wrote.

Hangar collects only the outputs that the package declares. Hangar lists the output folder without following links. Hangar records any other file name, link or folder as skipped, and does not read the skipped item. Hangar still seals and keeps an output that is larger than its max_bytes, and the output fails its descriptor.

The application connects to the network only through the gateway, and only to the destinations in the envelope. The containers of the job trust the certificate authority of the session, which vouches for those destinations only. SSL_CERT_FILE gives the path of the certificate authority file.

2. The package manifest

hangar_package.json describes the package. The file is JSON, in the format hangar-package-v1. Hangar refuses a field that Hangar does not know. A misspelt field is an error, and Hangar never drops a setting without a message. The schema docs/api/package-manifest.schema.json describes the file for editors. The parser in Hangar is the final authority.

FieldWhat it holds
formathangar-package-v1.
nameThe package name: a lower-case letter, then 1 to 62 lower-case letters, digits and underscores. Unique in your organisation.
versionMAJOR.MINOR.PATCH, digits only. A version never changes once created.
descriptionOne line about the package.
imagedigest, the sha256: digest of the image, and platform, linux/arm64 or linux/amd64.
entrypointThe program and its first arguments, as a list.
argumentsMore arguments, as a list.
resourcesvcpus, memory_mib, disk_gib, gpu (none or h100) and max_minutes, the longest one attempt runs.
inputsThe name and type descriptor of each input, with required.
outputsThe name and type descriptor of each output, with required. Every output is an artefact.
configEach configuration key, with the type descriptor, the default and site_specific.
envelopeThe envelope that the package asks for. See below.
sbomThe sha384: digest of the software bill of materials (SBOM) of the image. You upload the SBOM to Hangar.
runtimeThe Hangar runtime versions that the package supports: minimum, and below, the first version that the package does not support.
determinismdeterministic: the same inputs and configuration give the same output bytes. envelope: the outputs stay within the declared contract, and their bytes may differ.
self_testThe inputs of the acceptance self-test, and the outputs that the self-test must give.

The seven type descriptors

Inputs, outputs and configuration keys use a small set of descriptors that Hangar defines. The set is closed. A descriptor is one of these seven.

DescriptorFieldsA value matches when
stringmax_length; for a configuration key, destination: trueit is a string of at most max_length characters. With destination: true, it is the name of a destination the package declares.
integerminimum, maximumit is a whole number in the range. true and false are not numbers.
booleannoneit is true or false.
enumvaluesit is one of the listed strings.
objectfields, each a descriptor with requiredit has every required field, and no field the object does not name.
listitems (a descriptor), max_itemsit is a list of at most max_items items, each matching items.
artefactmedia_type, max_bytesit is an uploaded object of at most max_bytes, named by its sha384: digest.

An artefact is an input or an output, never a field of an object, a list item or a configuration key. Descriptors nest at most six deep.

Hangar refuses a job at submission with input_contract when an input does not match its descriptor. An output that does not match its descriptor fails the attempt with the reason output_contract. Hangar keeps the artefact under your retention, so you can see what the application wrote.

Artefacts travel as digests. The bytes pass through the upload routes into the storage of your organisation in Sydney. The envelope and the return list each artefact by digest, size and media type. The envelope and the return never contain the bytes of an artefact or any value.

The envelope the package asks for

The package asks for the permissions that it needs. The package never gives those permissions to itself. TALOS Warrant compiles the envelope from the request and your policies (Section 7).

FieldWhat it asks for
destinationsEach destination by its exact DNS name, with purpose, one sentence a person reads, and required.
data_scopesrun_inputs, the artefacts given as the job's inputs, or none.
secretsEach secret by name, bound to one declared destination, with the header the gateway sets and an optional scheme, and required.
companionsEach companion container by name and image digest. A companion runs in the instance of the attempt and uses the budget of the attempt.
model_routesEach model route by name, with its primary destination and an optional fallback, which is itself a declared destination.
person_presentThe steps that wait for a named person: action (destination_first_use, credential_use or agent_action), the target, and the sentence the approver reads.
computevcpus, memory_mib and max_minutes, equal to resources. A job can narrow these values. The package never asks for more than resources declares.
failureretries, from 0 to 3, and resume_from_checkpoint.

Hangar refuses a package version with envelope_request_invalid when the request binds a secret to an undeclared destination, gives a fallback that is not a declared destination, or has a malformed name. The error shows the item.

The CPU pool hosted-cpu-syd runs packages for linux/arm64 with gpu none. You send the image with hangar upload --image, and the manifest refers to the image by its digest.

hangar upload --image ./patch-agent.oci.tar --name patch-agent:1.0.0
hangar release create

hangar release create reads ./hangar_package.json (or the file that you name), sends the file byte for byte, and prints the package version with the manifest digest. The manifest digest is the domain-separated SHA-384 of the exact bytes, with the context hangar-package-v1. The command line computes the same digest on your machine.

3. Releases

A release pins one package version, by digest, under your signature. A release is a canonical CBOR document of the format hangar-app-release-v1:

FieldWhat it holds
vendorThe chain and name of your organisation.
package, versionThe package version that the release pins.
package manifest digestThe digest of hangar_package.json as you sent it.
imageThe image digest and its platform.
commandThe entrypoint and arguments.
resourcesAs the manifest declares them.
companionsEach companion by name and image digest.
SBOM digestThe software bill of materials.
envelope requestThe envelope the package asks for, in full, and its digest.
configuration schema digestThe digest of the declared configuration keys.
runtimeThe range of supported runtime versions.
determinismdeterministic or envelope.
sequenceYour release number for the package: 1, then one more for each release.
created atWhen the release was drafted.

The release id is the domain-separated SHA-384 of these bytes, with the context hangar-app-release-v1, written as sha384: and 96 hexadecimal digits. A release refers to an image only by digest, never by tag, and contains no configuration value. A changed image has a different digest, so it needs a different release with its own signatures. Pushing an image again under the same name changes no release, no channel and no job.

Your release key

You sign your releases with your own release key: a hybrid key pair of ML-DSA-87 and ECDSA P-256. hangar release keygen makes the key pair on your machine and keeps the private half there, in a file of mode 0600. The private half never leaves your machine. TALOS Defence cannot make or use the private half.

hangar release keygen talos-release
hangar release register talos-release

An owner of your organisation registers the public half, signed in with a passkey (POST /v1/vendor-keys). The registration is a record on the chain of your organisation. A request key cannot register a release key.

Signing and submitting

hangar release submit hangar_patch_agent@1.0.0 --key talos-release

The command line asks Hangar for a draft of the release (POST /v1/packages/{name}/versions/{version}/release-draft). Hangar builds the draft from the package version that Hangar holds, with the next sequence number. The command line checks that the draft matches hangar_package.json on your machine, signs the release id with your key, and submits the manifest and the signature (POST /v1/releases). Hangar accepts the submission when:

A release has these states in order: submitted, checking, checks_passed or checks_failed, then accepted or refused. A release later becomes revoked if someone revokes the release. hangar release status shows the state, and GET /v1/releases/{id} gives the release in full.

4. Acceptance

TALOS Defence runs the acceptance checks on every release before the release runs for a tenant. Acceptance shows that the checks passed for the digests in the release. Acceptance does not change the release. The signature of the vendor and the digests stay the same.

The checks that must pass:

CheckWhat it establishes
vendor_signatureThe release id is signed by a release key registered to the vendor and not revoked.
image_presentThe image and every companion are in the vendor's registry in Sydney under the digests the release names.
sbom_presentThe software bill of materials the release names is stored, under its digest.
envelope_requestThe envelope request is well formed: every destination is a valid name, every secret is bound to a declared destination, and every fallback is a declared destination.
configuration_schemaEvery configuration key has a valid descriptor, and a destination-typed key names declared destinations only.
runtime_rangeThe release's runtime range covers a runtime Hangar supports.
envelope_differenceHangar computes and records the difference from the release that each channel points at now (Section 5).
self_testThe self-test of the package ran on the CPU pool of this Hangar from the release itself, the return of the self-test verifies, and every expected output matched, by digest or by presence.

The self-test is a job of the release with the self_test inputs of the package and the default configuration. It runs on the platform of the pool, after the preflight of the image, so Hangar cannot accept an image that cannot start on the pool. The return of the self-test shows the notice "This return is a self-test of a release before TALOS Defence accepted it."

When the checks pass, a TALOS Defence operator accepts the release. The acceptance record lists every check by name with the result, the pool and return digest of the self-test, and any widening. TALOS Defence signs the acceptance record with the release root at the key site. TALOS Defence uses the release root only to sign what TALOS Defence ships. No customer data and no permission for any job depends on the release root. A root signature signs the acceptance, never a day key.

Hangar refuses a release whose checks fail. The release shows the checks and the results.

5. Channels, pins, widening and revocation

A channel is a name that you choose (stable, candidate, or any other name). The channel points from a package to one accepted release.

hangar release channel hangar_patch_agent stable 5d1c09e2a7b4

A move (POST /v1/packages/{name}/channels/{channel}) takes an accepted release only, and every move is a record. A job gives a release id (a pin), or a package and a channel. When you submit a job, Hangar resolves the channel to a release id once, and records the release id. Every retry of the job uses that release, even when someone moves the channel.

Widening

hangar_cert::envelope::diff compares two envelope requests and lists every widening, in a fixed order. A widening is one of these:

At every job, TALOS Warrant compares the release with the baseline of the tenant. The baseline is the newest release of the package that the tenant has run. When the tenant has not run the package yet, the baseline is the first accepted release of the package. The same rule applies to the jobs of your own organisation, which have no tenant. An owner must approve the difference for the tenant before a release that asks for more than the baseline can run for that tenant. Until then, the jobs of the tenant on the channel use the newest earlier release of the channel that stays within the baseline, and the job shows this in held_on. Hangar refuses a job of the widening release by id for that tenant with widening_not_approved, and the error detail shows the approval that an owner can decide. A release that narrows the permissions needs no approval.

The acceptance record and each channel move also list a widening, against the newest accepted release of the package and against the release that the channel pointed at. Those lists show what changed. The baseline sets the approval rule.

GET /v1/approvals lists each pending widening approval. Each entry shows the release, the package and version, the channel, the tenant, the baseline and every item that the release adds. The approval record shows the baseline and the items, so the record shows what the owner approved. The approver is an owner of the vendor's organisation, who acts for the tenant on the website or through the approval routes. The approval record shows the person and the tenant. The next job after the approval resolves to the new release, and the return of that job contains the approval record. The compiled record of every job shows the baseline, and the return contains the baseline release. hangar verify recomputes the widening offline and checks the approval.

Revocation

TALOS Defence or an owner of the vendor's organisation can revoke a release:

hangar release revoke 5d1c09e2a7b4 --reason "Wrong rule set"

A revocation is a record. Hangar holds a channel that points at a revoked release. Hangar refuses jobs on the channel with channel_held until you move the channel to an accepted release. Hangar never falls back to an earlier release by itself.

TALOS Defence signs the release revocation list with the release root and publishes the list at GET /v1/releases/revoked. When a vendor revokes a release of the vendor, Hangar holds the channels of the release at once. The signed list shows the revocation from the next signing. The list and the release key set (GET /v1/releases/keyset) are public, so a customer-controlled pool (offered from 2027) checks a release offline.

GET /v1/releases/{id}/bundle gives one release as a bundle that verifies offline: the signed release, the revocation list and the release key set. The vendor ships the image layers, as an OCI layout that the runtime checks by digest.

6. Site configuration

A package declares its configuration keys, and each pool and tenant sets the values. The same release id runs on every supported pool. One site differs from another in exactly three ways:

  1. a declared configuration key;
  2. the runtime version, inside the release's runtime range;
  3. the pool identity on the return.

Nothing else selects behaviour by tenant or site. A change for one customer is a configuration key, or a new package version for every customer.

PUT /v1/config/hangar_patch_agent/hosted-cpu-syd
{"tenant": "tnt_0192f3a1c7d84e6b9a0c5d2e1f4b7a93", "values": {"test_timeout_seconds": 300}}

PUT /v1/config/{package}/{pool} sets values for the organisation, or for one tenant with tenant. A value for a tenant wins over a value for the organisation. Each set makes a new configuration version with its own digest, and each set is a record. GET /v1/config/{package}/{pool}?tenant= gives the current version.

The rules:

TALOS Warrant compiles the digest of the configuration version into the envelope, and the return shows the digest. Two returns of one release on two sites show the same release id and different configuration digests.

7. Starting a job

hangar run --release 5d1c09e2a7b4 --tenant tnt_0192f3a1 \
    --input repository=sha384:9f2c41e0b37d --input rules='["path_traversal"]'

POST /v1/release-jobs, with an Idempotency-Key:

{
  "package": "hangar_patch_agent",
  "channel": "stable",
  "tenant": "tnt_0192f3a1c7d84e6b9a0c5d2e1f4b7a93",
  "pool": "hosted-cpu-syd",
  "inputs": {
    "repository": {"artefact": "sha384:9f2c41e0b37d..."},
    "rules": {"value": ["path_traversal"]}
  },
  "narrowing": {"max_minutes": 10},
  "client_ref": "harbour-17/2026-10-23/1"
}
FieldWhat it holds
release, or package and channelThe release id, or the package and the channel to resolve.
tenantThe tenant that the job serves. A request key that belongs to a tenant sends the same id in Hangar-Tenant.
poolThe pool, by name or id. The default is hosted-cpu-syd.
inputsEach input by name: {"artefact": "<digest>"} for an artefact, {"value": <JSON>} for the rest.
narrowingWhat the job gives up: the destinations, secrets and model_routes to keep, and lower vcpus, memory_mib, max_minutes and retries. Optional.
client_refYour own reference for the job, 1 to 128 characters, unique in your organisation and tenant.

client_ref lasts longer than the 24-hour idempotency store. The same client_ref with the same body returns the existing job. A process that restarts after sending finds the job, and starts no second job. Hangar refuses the same client_ref with a different body with client_ref_conflict.

Jobs of a release start on hosted-cpu-syd. Each attempt runs on one fresh Graviton instance in AWS Sydney, for that attempt alone. Hangar terminates the instance when the attempt ends. From 2027, a customer-controlled pool runs releases from the Hangar runtime of the customer, in the customer's environment (Pools, Section 3).

The compile

Before any instance launches, TALOS Warrant compiles the envelope, in this order:

  1. The release: the id, or the channel resolved once, with the widening rule of Section 5.
  2. The inputs, each against its descriptor.
  3. The release's envelope request.
  4. Your account policy: the egress list, and the release limits on vCPUs, memory, minutes, model routes and data scopes.
  5. The policy of the tenant, which can only narrow your account policy.
  6. The configuration version for the package, pool and tenant.
  7. The narrowing of the job, which can only remove items.

Each step is an intersection. The envelope never exceeds what any one step allows. When a policy denies a required item, Hangar refuses the job with envelope_denied, and the error shows the item. When a policy denies an optional item, Hangar drops the item and writes the drop, with the reason, in the envelope. Hangar refuses a narrowing that adds anything with narrowing_invalid. Hangar compares names exactly, so a name that differs in case or by a final dot is a different name.

The compiled envelope is canonical CBOR with its own digest. Hangar writes the envelope as a record before the launch. The envelope lists the release, the pool, the tenant, the image and command, the companions, the destinations, the dropped items, the data scopes, the secrets by name, the model routes, the person-present steps, the compute, the failure policy, the configuration digest and the inputs by digest. The envelope also lists the digests of the request, the account policy, the tenant policy and the narrowing that the envelope came from.

The window

Every envelope has a not-before time and a not-after time. The window is at most the max_minutes of one attempt plus 10 minutes to launch, multiplied by the number of attempts that the failure policy allows. Each attempt has its own hard stop: max_minutes plus the 10 minutes to launch, counted from the launch, and never later than the not-after time. At that stop, the authority for the attempt ends and the gateway closes. Hangar stops an attempt that still runs, and the attempt ends interrupted with the reason attempt_time_limit, or window_end at the not-after time. Hangar retries a stopped attempt while the window has room. No attempt starts after the not-after time, and a retry never extends the window.

Enforcement

The worker receives the compiled envelope and the digest of the envelope with the orders for the attempt. The worker refuses to start an attempt when the image, command, companions, platform, inputs, values or configuration differ from the envelope (envelope_mismatch). Nothing runs, and the return records the refusal.

The gateway list for the attempt is the destinations in the envelope, and the gateway attaches the secrets in the envelope. A model route compiles to the primary destination and the declared fallback of the route. The application chooses which destination to call. The gateway refuses every other destination.

A person-present step sends an approval request to the phones of the approvers. A declared credential_use or destination_first_use step turns the approval on for the whole attempt. An agent_action step uses the proposal that the agent sends to the gateway. The approval card shows the sentence of Hangar, with the sentence of the package beside it.

8. States and outcomes

A job moves through seven states:

StateWhat is happening
compilingTALOS Warrant is compiling the envelope.
queuedThe envelope is compiled, and the job waits for an attempt.
launchingA fresh instance is starting for the attempt.
stagingThe worker checks the orders against the envelope, and stages the image and the inputs.
runningThe application is running.
sealingThe worker seals and reports the outputs.
returnedThe job has ended, and Hangar has signed the return or is signing the return.

A returned job has one of five outcomes:

OutcomeWhat it means
succeededThe last attempt exited 0, the worker sealed every required output, each output passed its descriptor, and every output digest is in a record.
failedThe last attempt exited with another code, a required output failed its descriptor, or the worker refused the attempt. A job whose release is revoked before an attempt launches, or while it runs, also ends failed, with the reason release_revoked: Hangar launches no attempt and no retry of a revoked release, and stops the one running.
cancelledSomeone cancelled the job, or the tenant of the job was closed. Cancellation is final.
interruptedThe instance of the last attempt was lost, such as by a Spot reclamation, or the attempt reached its own time limit or the end of the window while the attempt ran, and no retry was left.
outcome_unknownThe application exited 0, but the worker did not report its outputs sealed, and no retry was left. Hangar cannot say that the outputs are whole, so Hangar never reports such a job as succeeded.

The retry rule: Hangar retries an attempt on a fresh instance when the attempt was interrupted, failed with a non-zero exit, or did not report its outputs sealed. Hangar retries up to the retries of the failure policy, while the window has room. Hangar never retries an attempt that was refused with envelope_mismatch, an output that failed with output_contract, or an image that the preflight refused, because a retry would repeat the same failure.

Each attempt has its own states: launching, staging, running, sealing and ended. Each attempt also has its own outcome and reason.

POST /v1/release-jobs/{id}/cancel stops the attempt and closes the envelope. Cancellation is final. A cancelled job starts no other attempt.

9. Events

GET /v1/release-jobs/{id}/events?after=<offset>&wait=<seconds> gives the events of the job after the offset as newline-delimited JSON (application/x-ndjson). Every line shows the offset (from 1), at (RFC 3339 with the Melbourne offset), the envelope digest and the kind:

KindFields
statestate, and outcome once the job returns.
compileddestinations and dropped, as counts.
attemptattempt, event (started or ended), pool, instance_type, zone, outcome and reason.
connectionattempt, destination, outcome (connected or refused), reason and connection_id.
approvalattempt, decision, proposal and approval_id.
artefactattempt, name, digest, size_bytes and descriptor.
{"offset":7,"at":"2026-10-23T15:12:47+11:00","envelope":"sha384:c41e...","kind":"connection","attempt":1,"destination":"pypi.org","outcome":"connected"}
{"offset":8,"at":"2026-10-23T15:12:52+11:00","envelope":"sha384:c41e...","kind":"connection","attempt":1,"destination":"example.com","outcome":"refused","reason":"not_on_allowlist"}
{"kind":"heartbeat","at":"2026-10-23T15:13:07+11:00"}

Each call answers as soon as an event exists after the offset. Otherwise the call answers after at most 15 seconds with one heartbeat line, which has no offset. To continue, call again with the last offset that you read as after. Hangar sends the events since that offset, with no gap and no duplicate, however many times you call or reconnect. The last line of a returned job is {"kind": "end", "state": "returned", "outcome": ...}. With wait=0, the call reads once and answers at once. Reading a returned job gives the remaining events and the end line, and never starts an attempt.

The stream contains metadata only, never input bytes or output bytes. hangar logs <job> --follow prints the stream.

10. The return

Every job ends with a return. The return is a job certificate of kind 4, printed as "job certificate, application release". The issuer of the key set of the pool signs the return. On the pools of Hangar, the issuer shown on each return is TALOS Defence Pty Ltd. Hangar signs a return after the machine is wiped, usually within 15 minutes after the last attempt seals. If you ask for the return before then, the API answers return_pending.

CallWhat it gives
GET /v1/release-jobs/{id}/returnThe return, as CBOR.
GET /v1/release-jobs/{id}/artefactsEach artefact with its digest, size, media type, descriptor result, attempt and content link.
GET /v1/objects/{digest}/contentThe bytes of an artefact, checked against the digest, for objects of at most 256 MiB.
GET /v1/certificates/{id}/reportThe report of the verifier on the return, checked with the published key sets.

The return lists:

A return contains no input or output bytes, no configuration value and no secret value.

What hangar verify checks

hangar verify 0192f3b7
hangar verify 0192f3b7.cert --release-keys release_keyset.cbor

hangar verify runs every check of the job certificate. For a return, it adds the release check:

"The release is signed by its vendor and accepted by TALOS Defence, the compiled envelope lies within the release's request, and every connection and output stays within it."

In order:

  1. The release manifest decodes, and the id of the manifest matches the return.
  2. The signature of the vendor verifies over the release id with the key in the included registration record.
  3. A root in the published release key set of TALOS Defence signed the acceptance, never a day key. The acceptance shows the release and the vendor key.
  4. The compiled envelope lies within the envelope request of the release, which the verifier recomputes. The envelope shows the release and the pool.
  5. The destination of every connection is in the envelope, and the destination of every model route is in the envelope.
  6. Every output digest is in an included record. A succeeded outcome has every output passed.

The hangar command line includes the release key set that TALOS Defence publishes. --release-keys FILE gives the command line another key set. The customer's own keys sign a return from a customer-controlled pool (offered from 2027). To check the return, run hangar verify --issuer-keys <customer key set>.

11. Errors

Every error has three parts, from the catalogue in docs/api/errors.json: what failed, the next step, and what to do if that fails. The codes these routes return:

CodeStatusWhen
package_manifest_invalid422The manifest has an unknown field, a bad name or version, or an output that is not an artefact.
image_not_by_digest422The manifest names an image by tag.
package_version_exists409The package already has that version.
package_not_found404No package of that name in your organisation.
package_recipe_not_offered422The image is not a pushed image named by digest.
platform_not_offered422The pool runs images for another platform.
placement_not_offered422The job names a placement other than hosted-cpu-syd.
pool_not_found404No pool of that name or id.
pool_runs_locally409The pool is customer-controlled; jobs start from its own runtime.
data_scope_not_offered422A data scope other than run_inputs or none.
envelope_request_invalid422The envelope request is not valid; the item is named.
input_contract422An input does not match its descriptor.
output_contract422An artefact does not match its descriptor.
vendor_not_enabled403Your organisation is not set up as a vendor.
vendor_key_invalid422The release key is not a valid ML-DSA-87 and P-256 pair.
vendor_key_not_found404No release key of that name in your organisation.
release_not_found404No release with that id in your organisation.
release_draft_mismatch422The manifest differs from the package version Hangar holds.
release_signature_invalid422The signature does not verify with a registered release key.
release_sequence_stale409The sequence number is not the next one.
release_not_accepted409TALOS Defence has not accepted the release.
release_revoked409The release was revoked.
channel_held409The channel's release was revoked.
channel_not_found404No channel of that name for the package.
widening_not_approved409The release asks for more than an owner approved for the tenant.
envelope_denied422Your policy denies an item the release requires.
narrowing_invalid422The narrowing adds an item.
config_missing422A configuration value the job needs is not set.
config_invalid422A configuration key is undeclared, or a value does not match its key.
client_ref_conflict409The client reference belongs to a job with a different request.
release_job_not_found404No job with that id in your organisation.
release_job_not_cancellable409The job has returned.
return_pending409The return is not signed yet. It is retryable.
envelope_mismatch409The worker refused orders that differ from the envelope.
job_token_invalid401The job token is not valid. The job token has expired, or Hangar revoked the job token with its job, tenant or key.
job_token_scope403A job token works only for its own job, with the capabilities that the job token has.
object_too_large_for_content413The object is larger than one content answer.
tenant_suspended409The tenant is suspended.
tenant_mismatch403The key or object belongs to another tenant.
revocation_list_stale409The pool's revocation list is older than its policy allows.

Read this page as Markdown