Every error code Seal uses, in the SDKs and inside a session: what it means and what to do about it.
SDK calls raise a Seal error. Requests inside a session get refused in the protocol's own terms: an HTTP status, a Postgres error or a Redis reply. Both use the same thirteen codes. The caller gets only the code and a fixed message; the full reason goes to your telemetry.
Retrying won't help with a "No" until something changes. Only Unavailable and SessionExpired are retryable.
Error
Meaning
Retry
What to do
Expired
The blob is past its expires time, or its tenant key version was retired.
No
Seal again and replace the blob. In Python, Node and Rust, reload_with (reloadWith in Node) picks up the new blob without a restart. See Rotating and revoking.
NotAllowed
No grant for the blob's apps, outside the network rule, grant removed mid-session, or no identity found.
No
Check grants with seal status and the reason in telemetry. See Apps and identities.
TierTooLow
The session is below the minimum tier the code or blob asked for. Higher tiers aren't available yet.
No
You only see this if you set a minimum tier.
IntegrityFailed
The executable hash missed the artifact check, or a signal suspended the identity.
No
Find the signal in telemetry. Wait out a timed suspension, or clear it with seal settings integrity clear.
Unavailable
Something couldn't be reached: a hosted replica starting from idle, a replica with no fresh state (fails closed), or the upstream. The SDK already tried every replica for up to two minutes.
Yes
Retry with backoff. If it lasts, check SEAL_ENDPOINT and telemetry.
PolicyDenied
A request is outside the blob's policy: path, method, --deny, method override, CONNECT or WebSocket, compressed response, Redis admin command. Usually an HTTP 403 inside the session.
A per-source rate limit. Plan budgets aren't enforced yet.
No
Slow down. A new session per request is the usual cause; open one and reuse it.
SessionExpired
The session's token ran out.
Yes
Nothing. The SDK restarts the session itself.
SessionEnded
Your close() or the integrity policy ended the session early. An HTTP connection gets a 401 and closes.
No
Start a new session.
VerificationFailed
The enclave's hardware report, release, guardian certificate or TLS key didn't check out. It can mean impersonation, so the SDK never retries quietly.
No
Check SEAL_ENDPOINT and any TLS-inspecting proxy. Otherwise, stop and look. See Enclaves and attestation.
BadRequest
The call is malformed: a bad to, app name, header or pin, a secret that breaks the secret rules, or a damaged blob.
No
Fix the calling code.
Internal
Seal itself failed. Details go only to telemetry.
Once
If it repeats, send the time and your tenant id to [email protected].
ResealRequired
The blob predates the platform this replica runs on, so it has no key for it.
No
Seal again. The new blob covers every enabled platform.
Expired
MeaningThe blob is past its expires time, or its tenant key version was retired.
RetryNo
What to doSeal again and replace the blob. In Python, Node and Rust, reload_with (reloadWith in Node) picks up the new blob without a restart. See Rotating and revoking.
NotAllowed
MeaningNo grant for the blob's apps, outside the network rule, grant removed mid-session, or no identity found.
RetryNo
What to doCheck grants with seal status and the reason in telemetry. See Apps and identities.
TierTooLow
MeaningThe session is below the minimum tier the code or blob asked for. Higher tiers aren't available yet.
RetryNo
What to doYou only see this if you set a minimum tier.
IntegrityFailed
MeaningThe executable hash missed the artifact check, or a signal suspended the identity.
RetryNo
What to doFind the signal in telemetry. Wait out a timed suspension, or clear it with seal settings integrity clear.
Unavailable
MeaningSomething couldn't be reached: a hosted replica starting from idle, a replica with no fresh state (fails closed), or the upstream. The SDK already tried every replica for up to two minutes.
RetryYes
What to doRetry with backoff. If it lasts, check SEAL_ENDPOINT and telemetry.
PolicyDenied
MeaningA request is outside the blob's policy: path, method, --deny, method override, CONNECT or WebSocket, compressed response, Redis admin command. Usually an HTTP 403 inside the session.
RetryNo
What to doFix the request. Limits lists every rule.
BudgetExceeded
MeaningA per-source rate limit. Plan budgets aren't enforced yet.
RetryNo
What to doSlow down. A new session per request is the usual cause; open one and reuse it.
SessionExpired
MeaningThe session's token ran out.
RetryYes
What to doNothing. The SDK restarts the session itself.
SessionEnded
MeaningYour close() or the integrity policy ended the session early. An HTTP connection gets a 401 and closes.
RetryNo
What to doStart a new session.
VerificationFailed
MeaningThe enclave's hardware report, release, guardian certificate or TLS key didn't check out. It can mean impersonation, so the SDK never retries quietly.
RetryNo
What to doCheck SEAL_ENDPOINT and any TLS-inspecting proxy. Otherwise, stop and look. See Enclaves and attestation.
BadRequest
MeaningThe call is malformed: a bad to, app name, header or pin, a secret that breaks the secret rules, or a damaged blob.
RetryNo
What to doFix the calling code.
Internal
MeaningSeal itself failed. Details go only to telemetry.
RetryOnce
What to doIf it repeats, send the time and your tenant id to [email protected].
ResealRequired
MeaningThe blob predates the platform this replica runs on, so it has no key for it.
RetryNo
What to doSeal again. The new blob covers every enabled platform.
Every SDK error carries a code, a retryable flag and a message.
import os, seal
try:
with seal.session(os.environ["OPENAI_API_BLOB"]) as s:
...
except seal.Expired:
# Seal the secret again and deploy the new blob
...
except seal.SealError as e:
print(e.code, e.retryable, e.message)
raise
import { Client, Expired, SealError } from"@sealzone/sdk";
const seal = awaitClient.fromEnv();
try {
const s = await seal.session(process.env.OPENAI_API_BLOB, { kind: "http" });
} catch (e) {
if (e instanceofExpired) {
// Seal the secret again and deploy the new blob
} elseif (e instanceofSealError) {
console.error(e.code, e.retryable, e.message);
}
throw e;
}
s, err := client.Session(ctx, blob, seal.WithKind(seal.KindHTTP))
if errors.Is(err, seal.ErrExpired) {
// Seal the secret again and deploy the new blob
}
var se *seal.Error
if errors.As(err, &se) {
log.Println(se.Code, se.Retryable(), se.Message)
}
match seal.session(&blob).http().await {
Ok(s) => { /* use s.url(), s.key() */ }
Err(e) if e.code() == seal::ErrorCode::Expired => {
// Seal the secret again and deploy the new blob
}
Err(e) => eprintln!("{:?} retryable={}: {e}", e.code(), e.code().retryable()),
}
Language
Shape
Python
One subclass of seal.SealError per code (seal.Expired, seal.NotAllowed, …) with .code, .retryable, .message. seal.BadRequest is also a ValueError.
Node
Classes from @sealzone/sdk extending SealError, with .code (the wire name, such as "not_allowed"), .retryable, .message.
Go
*seal.Error with Code, Message, Retryable(). Match with errors.Is against seal.ErrExpired through seal.ErrResealRequired.
Rust
seal::ClientError, with e.code() returning a seal::ErrorCode and ErrorCode::retryable().
Python
ShapeOne subclass of seal.SealError per code (seal.Expired, seal.NotAllowed, …) with .code, .retryable, .message. seal.BadRequest is also a ValueError.
Node
ShapeClasses from @sealzone/sdk extending SealError, with .code (the wire name, such as "not_allowed"), .retryable, .message.
Go
Shape*seal.Error with Code, Message, Retryable(). Match with errors.Is against seal.ErrExpired through seal.ErrResealRequired.
Rust
Shapeseal::ClientError, with e.code() returning a seal::ErrorCode and ErrorCode::retryable().
Your app talks to its usual client library, so refusals arrive in that protocol's format. Anything the upstream sends, its own errors included, passes through unchanged apart from key masking.
A command the blob doesn't allow gets -NOPERM seal policy_denied: …, and the connection stays open. When the session ends, the client gets -ERR seal <code>: … and the connection closes.
A refused session shows up as a Refused entry. A refused request shows up as a denied Request entry with the code. Filter the console's Telemetry page by app, identity, blob or event, or run seal telemetry --since 1h. Entries never hold the secret, bodies or upstream text.
Reason
What happened
Caller got
no_grant
The identity matches no grant for the blob's apps. The entry shows the identity seen.
NotAllowed
unknown_app_key
An app key that no grant names.
NotAllowed
outside_networks
Connected from outside the app's networks. The entry shows the address.
NotAllowed
grant_lost
A live session's grant was removed.
NotAllowed
bad_proof, token_expired
The identity proof didn't verify, or its token was too old.
NotAllowed
suspended
A signal suspended the identity. The entry shows the code and until when.
IntegrityFailed
artifact_mismatch
The executable hash isn't on the artifact list.
IntegrityFailed
blob_expired
Past the blob's expires time.
Expired
key_version_retired
The blob's tenant key version is retired.
Expired
not_sealed_for_platform
The blob predates this replica's platform.
ResealRequired
tier_too_low
The session's tier was below what was required.
TierTooLow
stale_state, no_state
The replica had no fresh tenant state.
Unavailable
unavailable
A service didn't answer: the control plane, the key guardian or an identity issuer.
Unavailable
malformed
The request was malformed. The entry says how.
BadRequest
no_grant
What happenedThe identity matches no grant for the blob's apps. The entry shows the identity seen.
Caller gotNotAllowed
unknown_app_key
What happenedAn app key that no grant names.
Caller gotNotAllowed
outside_networks
What happenedConnected from outside the app's networks. The entry shows the address.
Caller gotNotAllowed
grant_lost
What happenedA live session's grant was removed.
Caller gotNotAllowed
bad_proof, token_expired
What happenedThe identity proof didn't verify, or its token was too old.
Caller gotNotAllowed
suspended
What happenedA signal suspended the identity. The entry shows the code and until when.
Caller gotIntegrityFailed
artifact_mismatch
What happenedThe executable hash isn't on the artifact list.
Caller gotIntegrityFailed
blob_expired
What happenedPast the blob's expires time.
Caller gotExpired
key_version_retired
What happenedThe blob's tenant key version is retired.
Caller gotExpired
not_sealed_for_platform
What happenedThe blob predates this replica's platform.
Caller gotResealRequired
tier_too_low
What happenedThe session's tier was below what was required.
Caller gotTierTooLow
stale_state, no_state
What happenedThe replica had no fresh tenant state.
Caller gotUnavailable
unavailable
What happenedA service didn't answer: the control plane, the key guardian or an identity issuer.
Caller gotUnavailable
malformed
What happenedThe request was malformed. The entry says how.