Weles/Docs

Reference

Every way a Weles operation fails, and what fixes it.

Generated from the failure catalogues weles 0.8.0 declares (weles errors list --json). Each cause names what failed, why, the state the refusal shows, the fix, its code and statuses, and the test that provokes it.

Operations#

Each operation below declares every way it fails, including the ways nobody has met yet. A refusal prints `weles: <what failed>: <why>; observed: <state>`, then `fix:` and the cause, and exits 2 for a refusal of the request's own form, 69 when retrying unchanged can help, 1 otherwise; with --json the same cause is printed as one JSON document. `weles errors show <operation>` prints a catalogue; `weles errors check` refuses a cause without its fix or its test and an error message that names no failed step.

Operations that declare their failures (weles 0.8.0)
OperationStarted throughCausesWhat it does
accounts.login-accountthe operations that use it17Resolve the subscription a caller names to the one account and login that sign it in, read that login's material for the sign-in, and keep the grant it earned on the subscription.
accounts.sign-inweles accounts list [--provider <provider>], weles accounts refresh --provider <provider> --subscription <id>, weles accounts logout --provider <provider> --subscription <id>4List the accounts the vault's subscriptions resolve to, refresh one account's sign-in on the managed executor, and sign one out by erasing the grant the vault holds for it.
accounts.sessiona trajectory signing an account in or registering it (resolveAccountSession)4Restore an account's proxy exit and persona before its browser starts, so its sign-ins look like the same device.
accounts.pinneda trajectory signing an account in or registering it (resolveAccountSession)8Read the proxy pinned to an account, refusing a burned, retired or failing exit, and write back what the session assigned.
accounts.sociala trajectory that signs in with a social account (getSocialAccount), a session whose cookies were refused (markCookiesStale)2Choose the account a run signs in with, and mark its cookies stale so its login runs again.
mail.alternativea session reading a sign-up mail, the Google app password run handing its password to Skrzynka, a PARP sign-in reading its mailbox2Find the Skrzynka program through the mail alternative Stado names for Weles.
mail.programevery Skrzynka command Weles runs: reading an inbox, listing and syncing mailboxes4Run one Skrzynka command for an organization and read its JSON answer, relaying its refusal with its code.
mail.inboxa session waiting for a sign-up code or link (check_email)2Read the messages Skrzynka holds for an address, newest first, from the sender a session waits on.
mail.domaina trajectory registering an account on a new address3Pick the inbound domain a new account's address is made on, least used first, skipping broken and blocked ones.
proxy.pina trajectory signing an account in or registering it (resolveAccountSession)13Rebuild an account's pinned proxy from what its pin states and prove it still opens a tunnel to the platform.
proxy.exit-geographyWSession.start of a session without a proxy (openSessionBrowser)4Ask the geography lookup where an exit is: the country, timezone and network of a proxy exit address, or of this host itself for a session that runs without a proxy.
trajectories.parp-loginthe feng/auth/parp_login trajectory7Sign in to lsi.parp.gov.pl by asking a password reset and setting the new password, kept only in the vault item its managed declaration names, from the reset mail.
run.apple-capabilitiesPOST /run of an Apple login, agreement or certificate action, the guarded Apple run (apple/guarded/run.mjs)5Read the email, password and two-factor capabilities an Apple run is bound to, before anything is filled.
identity.smsa session that needs a phone number (WSession getPhoneNumber), discord phone verification4Rent a phone number in the country asked from the first SMS provider that holds one, and read the code texted to it.
identity.sms-providerrenting a number, reading its code and releasing it, at JuicySMS or SMS-Activate8Ask one SMS provider's HTTP API, with the key the vault holds, never quoting the key.
accounts.acquiredclaude/account/acquire2Record a bought account as its login row and Brama subscription item before it is signed in.
captcha.providerevery captcha a session solves through a service15Ask each solving service whose key Weles holds, receive its answer at the run callback, and record the price of the one that solved.
captcha.proxya captcha task solved through the run's proxy4Hand a solving service the proxy the token must be solved from, as address, port and login.
captcha.recaptchaa session solving reCAPTCHA v2 in the page or as a token10Solve reCAPTCHA's image grid in the page, choosing the tiles by solving services and the vision model, or get a token from a service.
secrets.managed-passwordsevery credential write and read of a managed password (Microsoft, Microsoft Entra, PARP)8Read the deployment-owned list of accounts whose passwords Weles writes and reads, from one owner-only file.
secrets.capabilitya browser step filling a credential (fill_credential), a captcha, SMS or Apple two-factor step redeeming its capability24Check the one-shot capability a run was handed and redeem or cancel it at the Skarbiec broker as this workload.
proxy.public-addressweles doctor, the machine's public address, a proxy exit preflight3Ask the declared plain-text service which public address this host, or an exit, browses from.
runtime.costevery run that records a captcha, SMS or proxy cost5Keep the run's captcha, SMS and proxy costs in its rollup file under recordings/_costs.
human.timinga browser session moving the pointer or typing2Draw the pauses and choices of human-like input from the run's recorded seed, so a run can be replayed.
accounts.observedweles accounts billing [--provider <provider>] [--account <account>], weles accounts quota [--provider <provider>] [--account <account>]0Read the billing (plan, status, cost, invoices) and the quota Weles observed on the provider's own pages for each subscription it collected, as the subscription records hold them.
reauth.admissionthe operations that use it5Admit a request to the Weles API's account routes: Brama's reauth bearer, the provider and the subscription it names, and the account revision the caller resolved.
reauth.sign-inPOST /reauth, POST /reauth/resolve, POST /reauth/logout2Sign one subscription's account in again on this host, resolve it without signing in, or sign it out by erasing the grant the vault holds for it.
reauth.sign-in-outcomethe operations that use it5Say why a sign-in run that started ended without a grant, in the failure of its last result line.
reauth.accountsPOST /reauth/accounts, POST /subscriptions/billing, POST /subscriptions/quota0List the accounts the vault's subscriptions resolve to, of one provider or of every provider, and the billing and quota Weles observed for each subscription it collected.
reauth.subscription-runsPOST /subscriptions/acquire, POST /reauth/authorize8Buy a new account of a provider and sign it in for Brama, or complete one OAuth authorization a coding-agent harness started for an account the pool holds, answering the provider's redirect to the harness.
admission.callerthe operations that use it2Authenticate the caller of a public task route: the bearer is the Spis admission token this worker was started with.
admission.requestthe operations that use it6Read the body of a public task request: JSON under a declared media type and an Idempotency-Key, for the organization the bearer admits.
admission.lookupthe operations that use it2Find one public task by the id its submission answered: the id is a UUID and this worker holds its record.
admission.submitPOST /api/v1/tasks37Admit one public browser-evidence task: the request is authenticated, its form and its Spis binding are checked, the deployed service identity and the page host are verified, and the task is recorded and queued.
tasks.documentthe operations that use it2Read one JSON object a task or receipt command is given as a file, or - for standard input.
tasks.publicweles tasks submit --request <file|-> (--consumer <consumer> | --endpoint <url>) --role <role> [--idempotency-key <key>], weles tasks show <task-id> (--consumer <consumer> | --endpoint <url>) --role <role>, weles tasks await <task-id> (--consumer <consumer> | --endpoint <url>) --role <role>, weles tasks cancel <task-id> --reason <text> (--consumer <consumer> | --endpoint <url>) --role <role> [--idempotency-key <key>]3Submit a browser-evidence task to the public task API, read it, wait until it ends, or cancel it, with the bearer of the item playing the caller's role, answering what the API answered.
receipts.verifyweles receipts verify --receipt <file|-> --keys <file>10Verify one signed receipt of any outcome against a map of trusted public keys, offline, and print the claims it signed.
admission.statusGET /api/v1/tasks/<task-id>4Read one public task, or with ?wait=terminal hold the answer until it ends; a terminal task carries its signed receipt.
admission.cancelPOST /api/v1/tasks/<task-id>/cancel4Cancel one public task: a queued task ends cancelled at once, a running one is stopped and ends cancelled, a terminal one is answered as it ended.
browser.releaserequireBrowserRelease, selectedBrowserVersion14Find the executable of the selected, checksum-verified weles-chromium or weles-firefox release: the deployment's pin or the host's selection record, used only when the install's receipt matches it.
browser.enginethe operations that use it23Launch a Weles browser and act on its pages, every failure the engine reports classified by its own words and quoted whole.
session.launchWSession.start, openSessionBrowser, accountProfileDirectory, loadOperatorCdpConfig11Bring up the browser of a WSession: resolve its proxy, file its account's profile, adopt the operator's browser or launch the selected release, and attach the protocol observers.
session.cookiesSessionStore, personaSignature, proxySignature5Keep each session label's cookies in the vault setting browser_sessions, put them into a new browser, and sign the persona and egress a cookie jar was minted under.
session.inputWSession.click, WSession.fill, WSession.fillSelector, WSession.waitFor, WSession.patchAccount, WSession.fillIdentity, WSession.textedCode, resolvedPlaceholders12Act on a WSession's page as a person would: click and fill the control a step names, type only into a field whose markup allows it, and put in the values the session generated or rented.
session.credential-fillWSession.fillCredential, WSession.fillIdentity, assertLiteralControl11Put a credential a capability names, or a generated identity value, into the one page field whose own markup declares its class, and refuse literal text into such a field.
session.capturescrubHar, writeJsonFile, attachInstrumentationCheckpoints, captureStepArtifacts12Write what a WSession recorded: its HAR with the request bodies withheld, the instrumentation artifacts, each frame's instrumentation log, and why a failed step has no artifacts.
agent.inferencePOST /run, a run whose step asks a model, weles mcp, a page question, a trajectory generating text or an image6Hand one model request to Stado's inference alternatives and read the answer and the alternative that gave it.
agent.modelPOST /run, a run whose step asks a model, weles mcp, a page question, a trajectory asking a model5Ask a model one question, with the page's images and the functions it may call, and read its text or its one function call.
agent.draftPOST /run, a draft-first run, POST /run with WELES_TRAJECTORY_RECORDING set7Ask the model for a draft-first run's trajectory and read its steps and notes.
agent.flowsFetchAccountValue, the generic vision login (agent login.run), the typed vision extractors12Sign in with the generic vision login, read one account value, keep its learned route, and read typed values off a page.
agent.toolsdispatch8Run one browser tool call an agent's model made on its WSession, refusing an argument the tool does not take before anything acts.
agent.decisionaskLlm5Read the browser tool and its arguments the model chose as an agent's next step.
agent.loopPOST /run, a generic_browser_task run, execute (the browser agent of the library)10Run one browser task step by step (replayed or chosen by the model) until done, keeping every step taken.
vision.screenshota page question (askPage, checkPage, identifyPage, findClickTarget), weles mcp, a page question5Capture the page a question is asked about as a PNG, through its screenshot() or the DevTools connection.
vision.questiona page question (askPage, checkPage, identifyPage, findClickTarget), weles mcp, a page question, POST /run, a step that asks about the page12Ask a vision model one question about the page, recorded in the run's vision folder, escalating a refusal to the screenshot's transcription.
proxy.addressesloadSpecialAddresses, specialBlockOf, assertGloballyReachable11Judge whether a network address is public by IANA's Special-Purpose Address Registries, read once per process, naming the block an address falls in.
agent.evidence-targetinstallBrowserEvidencePolicy, configuredTarget, publicAddresses, resolveBrowserEvidenceTarget, enforceBrowserEvidenceToolPolicy15Hold a browser-evidence run to the one public https origin and address set it was admitted with: every other request is withheld into its ledger, and so is every interactive tool the policy does not admit.
browser.sessionweles mcp8Drive a Weles browser one operation at a time over JSON-RPC: start a browser, open pages in it and navigate, read, act and assert on them by the ids the server hands out.
browser.openweles open <url>3Open one page in a browser launched from the command line, and answer its address, title and HTTP status, with a screenshot and its text when asked.
executor.requestthe operations that use it16Reach the managed Weles executor from an operator's shell: find it through Stado's service directory or WELES_WORKER_API_BASE, read its bearer, send the request and read its JSON answer.
executor.runthe operations that use it4Start one trajectory as a detached run on the managed Weles executor and read its persisted record back: the answer must start the run that was asked, and the record must be that run's, bound to the request that started it.
run.requestPOST /run12Admit one run of a named trajectory: its action, how its output is answered, its parameters and the Google login they name, its account and profile, and when detached the id it is read back by.
run.answerPOST /run3Answer a run the request waited for: the accounts it saved, its redacted outcome, or its raw result.
run.builderPOST /weles-builder3Turn a goal stated in prose into a run of the browser agent from a neutral page, whose executed steps become a new reusable trajectory.
runs.manageweles runs list, weles runs show <run-id>, weles runs answer <run-id>, weles runs cancel <run-id>, GET /runs, GET /runs/<run-id>, POST /runs/<run-id>/answer, POST /runs/<run-id>/cancel15Attend the managed worker's runs: list each run it has a live child for and what it waits for, read one run's record, tell a run waiting for a person what the person did, and cancel a run with who and why.
security.accountweles security --provider google --login-role, weles security --run6Read whether a Google account has two-step verification on, without changing it: start google_mfa_status on the managed executor for the Skarbiec login a role names, and read the run's persisted observation back.
identity.passwordthe operations that use it5Generate the password of an account Weles registers or resets: one character of every class, the rest from all of them, at the length the vault policy or WELES_GENERATED_PASSWORD_LENGTH states.
password.appweles password --provider google --login-role, weles password --provider google --login-item, weles password --run7Issue a Google app password for Skrzynka: start google_app_password on the managed executor for the Skarbiec login a role or item names, bound to the Skrzynka organization and the mailbox account named, and read the run's record back.
oauth-callback.appweles oauth-callback --provider google --login-role, weles oauth-callback --provider google --login-item, weles oauth-callback --run8Make one OAuth client accept a new callback address: start google_oauth_callback on the managed executor for the owner's Skarbiec login and the item holding the client, each by role or item, with the https callback, and read the run's record back.
sign-in.authorizationthe operations that use it16Read the command line of one authorized Apple run, take the operator confirmation in words, have Stado issue three one-use capabilities on the execution host, start the run on the executor, and read it back with --run.
sign-in.appleweles login --provider apple, weles login --run <run-id>0Sign one Skarbiec Apple account in on a Stado host, in one authorized run, and read the run back.
sign-in.agreementweles agreement --provider apple, weles agreement --run <run-id>0Have the Apple Account Holder accept the updated Developer Program License Agreement, in one authorized run, and read the run back; Apple refuses the team's provisioning until it is accepted.
certificate.appleweles certificate --provider apple, weles certificate --run <run-id> --certificate-out <file>11Issue one Apple Developer ID Application certificate: the key and request are made on this machine, one authorized run has the Account Holder issue it in the portal, and --run writes the certificate and, with --private-key and --store-host, keeps the identity in the vault the release recipes read.
worker.controlweles worker status, weles worker version, weles worker start, weles worker stop, weles worker restart, GET /worker/status, GET /worker/version, POST /worker/start, POST /worker/stop, POST /worker/restart9Read and control the managed worker: what deployment answers and its process, the resident task dispatcher's state, and stopping, starting or restarting that dispatcher in the same process.
worker.launchnode src/worker/weles-api-launcher.mjs9Start the Weles API as its unit runs it: read the declared address, refuse a port another process holds, retire the units it replaces, check the release's declarations, acquire the startup secrets and declare Weles's capability routes.
worker.apithe operations that use it8Admit a request to the Weles API's token routes and read it: the bearer it carries, the address it names and the body's JSON and fields.
worker.request-bodyreadBody, readText1Read a request's whole body off its connection, for the route to parse.
worker.diagnosticsGET /diagnostics/<run>, GET /diagnostics/<run>/file?path=<file>[&wait=terminal]4Answer a run's evidence: its manifest, one file of it, or the run outcome once the run has one.
worker.run-evidencethe operations that use it10Read what a run left on this worker: the recording roots its evidence may live under, one file of it, the named documents it recorded, and its persisted outcome, waiting for the outcome when asked.
worker.captcha-answerPOST /captcha/answers/<run>/<token>2Keep the answer a captcha provider pushes for a task a run of this worker created, for that run to read.
worker.servenode src/worker/weles-api-server.mjs12Start the Weles API process: prove the release it answers under and read the settings its service declaration states, before the port is bound.
settings.valuethe operations that use it4Read a setting a Weles process is started with by name: required text, a secret long enough to sign with, a TCP port, or a whole count.
settings.originthe operations that use it7Read the origin of a service a Weles process reaches: HTTPS, or plain HTTP to this machine's loopback, without credentials, path, query or fragment.
worker.pagesPOST /pages/snapshot, POST /pages/form-export10Read or export a rendered public page in the worker's own browser: admit the target, load it, and read it or fill its form and take the file it downloads.
worker.recordsPOST /records/accounts/list, POST /records/accounts/get, POST /records/accounts/upsert, POST /records/accounts/update, POST /records/settings/get, POST /records/settings/set, POST /records/services/list1Serve the trajectory accounts, runtime settings and service records Weles keeps in its vault to the products that manage them.
errors.catalogueweles errors list, weles errors show, weles errors check6Print every way a Weles functionality can fail, as it declares it, and hold a checkout to the error standard: complete causes, a real or listed test for each, and no generic failure sentence in the source.
cli.commandweles <command>, weles onboarding <action>, weles import <trajectory-export.json> --host <host>, weles sources [discover <adapter> <file>], weles release <action>, weles design <action> --provider figma, weles version, weles doctor9Read the weles command line into one command, its action, arguments and required options, and identify the installed release from the package manifest beside its dist.
recordings.rootthe operations that use it2Find the directory run recordings live in: WELES_RECORDINGS_ROOT names it, and it must be a directory this user can read.
recordings.writethe operations that use it8Write one file of a run's recordings: create the run's directory, write the file under a temporary name beside it and rename it into place, so a refused write leaves the old file.
recordings.scrubweles recordings scrub3Rewrite every stored run's session_meta.json so no environment value stays on disk: env_all becomes env_names, the sorted names alone, and every file changed, or left unread or unwritten, is reported.
pointer.tracethe operations that use it2Read the pointer trace Weles moves by: the packaged parts src/human/pointer/pointer-trace/, or the directory of parts or JSON file WELES_POINTER_TRACE names.
pointer.harvestweles pointer harvest, weles pointer show8Harvest the pointer travel between presses and the wheel steps from instrumentation dumps of runs a person drove into the trace Weles ships, and show what the trace holds.
parts.readthe operations that use it6Read a JSON document kept as a directory of numbered parts, merging them in name order: arrays continue across parts, objects gain each part's keys.
keeper.socketthe operations that use it9Reach a keeper by its session: the session names one directory, its socket path fits the system limit, a keeper listens there and answers one JSON line.
keeper.controlweles keeper start --session <id> [--url <url>] [--headless], weles keeper status --session <id>, weles keeper stop --session <id>, GET /keepers, GET /keepers/<session>, POST /keepers/<session>/stop11Start one keeper for a session and serve its socket until it is stopped, read whether it runs and what it does, and stop it, closing its browser and finishing its evidence before the stop is confirmed.
keeper.commandone JSON command line on ~/.weles/keeper/<id>/socket, trajectory keeper/action (SESSION, the command on stdin)9Run one command in a running keeper through the humanized atoms: navigate, settle, click, fill, type, press, scroll, ask the vision model, evaluate, read cookies or save a screenshot.
onboarding.journeyweles onboarding status|next|reset, weles onboarding import <trajectory-export.json> --host <host>, weles onboarding verify --receipt <file> --keys <file>6Walk an operator through the authorization boundary, the import of existing trajectory exports and approved host execution, completed by verifying a real workflow receipt against trusted keys.
onboarding.stepsweles onboarding status|next|import|verify|reset, runWelesOnboarding({ action })12Take one step of Weles's first-use journey: read where it stands, advance it, record an import, verify a receipt or start again.
onboarding.storageweles onboarding status|next|import|verify|reset --state-dir <dir>7Keep the first-use journey's bundle, progress and queued events in its state directory: read every file as JSON, check the journal, and publish each change as the next version.
onboarding.planeweles onboarding status|next|import|verify|reset (with WELES_STADO_INTEGRATION_TOKEN set)10Reach the onboarding control plane Stado names for onboarding-events: read the journey bundle and state, assign an experiment and send each queued event.
onboarding.runtimeweles onboarding status|next|import|verify|reset11Check the journey bundle an attempt runs, choose the next screen of its definition, and keep a started attempt's progress and events.
imports.trajectoriesweles import <trajectory-export.json> --host <host>, weles onboarding import <trajectory-export.json> --host <host>, POST /imports10Import existing trajectory exports as drafts bound to one managed worker: read the export, send it to the Weles web API's /api/v1/imports and read the report of what it imported, left unchanged or refused.
secrets.alternativethe operations that use it16Reach the vault through the secrets alternative Stado names for Weles: resolve it, prove it again when it stops answering, and read and write items through Skarbiec's consumer routes as the consumer weles with the bearer of the grant Stado declares for it, or, when Stado hands out the owner-only credential file, through `stado credentials ls|get|put|rm`.
secrets.scopedthe operations that use it12Read and write a trajectory's own service credentials as the service catalog declares them: each field from the vault the secrets alternative names, and each write through `stado credentials put --role`.
skarbiec.runtimenode src/_shared/vaulting/skarbiec-runtime.mjs active-binary|endpoint|capability-socket6Find the Skarbiec of this host as Stado declares it: the attested program, the route of the secrets alternative Stado names for Weles, and the capability socket of its unit.
broker.statusnode src/worker/weles-api-launcher.mjs6Ask the Skarbiec capability broker of this machine, on the socket Stado declares for its Skarbiec unit, whether it listens, before the Weles API issues capabilities into its state.
integrations.actionnode src/trajectories/slack/rename_app.mjs, node src/trajectories/slack/post_message.mjs, node src/trajectories/resend/verify_domain_status.mjs, node src/trajectories/meta/ads/ads_performance.mjs9Act through Wisent Integrations as the alternative Stado names for the action's family: the Slack app's actions, the receiving provider's mail list, the Resend domain checks and the Meta ads reads and uploads.
skarbiec.vaultthe operations that use it8Read and write the vault through the secrets alternative Stado names: the item inventory, documents, tags, policy, the item playing a role, and the records and settings Weles keeps.
skarbiec.recordsweles records adopt [--json]0Tag every Weles record in this vault that carries no weles:record:<kind> tag with the kind its own context names, keeping the tags it carries.
records.subscriptionnode src/lib/subscribing/service_subscriptions.mjs list|get <id>|upsert '<row-json>'|update <id> '<patch-json>'|delete <id>9Keep the subscriptions Weles observed, one vault record each, found by service, provider and account: what the collector observed and when, never filled in.
records.credentialnode src/lib/service_credentials.mjs list [term,term]|patch <id> <json>|ensure-kimi-google-sso <id> [source] [email]7Keep the service credentials Weles signs in with, one vault login item each, listing them without their passwords.
doctor.checkweles doctor [--json]12Check this install as a worker will use it: the vault route the secrets alternative names, the recording runtime every browser task needs, the running Weles API against the installed release, and the login inventory.
capture.paramsPOST /run generic_capture, POST /run generic_accessibility_audit, trajectory generic/capture and generic/accessibility_audit (their plan in the environment)13Read the plan of one capture or accessibility audit: the page, the axis, the viewport, the steps, the seconds of video and where its artifacts go.
release.documentthe operations that use it3Read the JSON documents a release judgement works on, from paths the caller names or the checkout holds, and write back the ones it keeps.
release.surfaceweles release surface11Read everything a build publishes -- library exports, CLI commands, MCP tools, worker HTTP routes, API schemas, task statuses -- from a checkout's source through the TypeScript program, with the version it declares as released.
release.enforceweles release enforce9Pass a release only when AutoVersion's decision, the released baseline, the version declaration and the package manifest say the same thing.
release.validateweles release validate5Judge a candidate deployment manifest against the weles.deployment.v2 contract, the revision the release is for and the tag cut for it.
release.adoptweles release adopt, node scripts/release/version/adopt-published.mjs10Record a published release as the baseline the version gate judges against: the surface its build carried and the version it was published as, read from the release Stado serves or named by hand.
trajectories.requirements-publishnode src/trajectories/publish-requirements.mjs8Publish the trajectory capability declaration to the fleet byte for byte: check it, write it through `stado storage put` and read it back through `stado storage get`.
trajectories.inputsthe operations that use it6Read what a run's caller states in the environment: counts, budgets, numbers, text, one of a trajectory's choices and JSON documents, refusing an unset or misshapen one by name before anything is opened.
trajectories.pagethe operations that use it11The page steps every trajectory shares: write a field and read it back, take a control once, fit a value into its field, find a row or control a model judges, read across a navigation, wait out an operator review, print an address.
trajectories.overleafthe operations that use it1Read Overleaf's dashboard: every project it lists, its load-more control pressed until a settled page shows no more rows.
trajectories.engagementthe operations that use it10Act on a platform as one of its accounts, probe an account's health, or read a declared observation, and read the platform's ban detector afterwards.
trajectories.documentweles documents list, weles documents prune9Check a document a reviewed trajectory downloaded against its declared media type and keep it, readable by its owner alone, in its own directory; list the copies kept and prune the older ones.
trajectories.google-sign-inthe operations that use it20Sign in to Google as a stored login: read the login and its authenticator seed, type the identifier and password, answer the second factor and decline Google's offers after sign-in.
trajectories.apple-adsnode src/trajectories/apple/ads/run.mjs9Run one Apple Ads action as the asc ads command the catalogue of actions declares, built from the run's stated inputs and gated when it changes something.
trajectories.avatarthe operations that use it3Load the avatar a profile edit uploads: the character's private stado://weles/avatars object, made upright and cut to a square, kept as a file for the browser.
trajectories.mediaa trajectory posting an image (instagram content post)2Generate the image a post carries through Stado's inference alternatives and keep it in the run's recordings.
objects.storethe operations that use it17Write one private Stado object at its canonical stado:// address, with the receipt acknowledging exactly those bytes, and stream it back to compare its size and digest.
objects.uploadthe operations that use it4Mirror every file under a run's recordings into private Stado objects with its relative path intact, and write the run's upload proof once every object is acknowledged.
artifacts.locatorsnormalizeArtifactLocators8Check a run's artifact locators: one list per declared kind, each locator a private stado://weles/recordings/<run uuid>/<path> URI, before the client asks for them to be signed and before the delivery service signs them.
artifacts.signed-urlsrequestSignedArtifactUrls8Have the artifact delivery service sign a run's private artifact locators: the locators are checked first, and every signed URL it answers must sign exactly the locator it stands for, at the service's origin, before its expiry.
artifacts.deliveryloadArtifactDeliveryConfig, createArtifactDeliveryServer, handleArtifactDeliveryRequest16Serve a run's private artifacts: list the subscriptions Oko's console reads, sign a run's locators for a limited time, and admit an object URL only while its signature and expiry hold.
artifacts.object-streamdeliverObject9Stream one private object out of Stado's object API to the holder of its signed URL, passing its range, type and size through and offering HTML only as a download.
skarbiec.acquisitionnode src/worker/deploy/acquire/skarbiec-acquire.mjs <scope-file> <consumer> <item> <field>23Acquire one field for one consumer as the workload this host runs: a scope the catalog declares, a signed proof, a field-bound bearer and the one-time read it redeems.
skarbiec.writenode src/worker/deploy/acquire/skarbiec-write.mjs <consumer> <item|role:ROLE> <field> <absolute-token-file> <operation> <operation-id>13Write one captured credential into Skarbiec as the exact Weles writer consumer: a whole new item for an acquisition, the one field for any other operation.
admission.service-identityGET /api/v1/version11Read which published public service this host is: the placement policy, the service-directory snapshot and the local transport Stado publishes, each checked against this release.
release.deployment-identityGET /worker/version, weles worker version5Read the immutable release identity a worker was deployed with (its version, revision, digests, ring and claims switch) and its instance id, as GET /worker/version answers them.
executor.submitthe operations that use it5Start a run one run asks for as a detached POST /run on the Weles API this process belongs to, and read its persisted result back.
admission.statethe operations that use it13Keep the public tasks' durable state: task files and Idempotency-Key reservations written atomically and recovered at start, and each task's wire answer and canonical JSON built from them.
admission.retentioncreateEvidenceRetention21Retain a finished public task's browser evidence: hash the run directory, write the manifest, have durable storage acknowledge and read back every object, and sign the receipt over exactly those bytes.
credentials.operationPOST /api/v1/credential-operations53Run one credential operation another product asks for: admit its bearer through Skarbiec's introspection, match the request to the acquisition Weles declares (or, for an authenticator enrolment, start the run the owner's order allows, pass it the owner's answers and say where it stands), run it once, and answer its status from the worker's record.
secrets.bindingcheckedTokenFile, checkedTenantDirectory, checkedTenantFile4Read what Weles reaches Skarbiec with: the owner-only token files Stado issues and a tenant's binding directory and files.
worker.routesstatusOf, captchaAnswersOf2Build the worker's routes: the HTTP statuses from Node's table and the captcha answers directory of each run.
credentials.capturestore_credential, wsStoreCredential, wsAutoStoreCredential17Capture the credential a provider page shows, on the authorized origin and of the contract's shape, and store it in the one Skarbiec item its acquisition names.
browser.controlsresolveObservedControl, clickObservedControl, clickSelectorControl7Bind the control a step names to exactly one element: an observed description to the element that still has it, a selector to the one visible element it matches.
declarations.loadweles API launcher: load engagement declaration, weles API launcher: load observation declaration, weles API launcher: load document declaration10Read and check the whole engagement, observation or document declaration when the API launcher starts.
declarations.admitPOST /run generic_saved_task, POST /run generic_keeper_task, POST /run generic_document_task6Admit a generic run by the declared engagement, observation or document it names, before anything is spawned.
trajectories.runnode src/trajectories/<provider>/<action>.mjs, POST /run0Run one trajectory as its own process; a declared refusal it raises ends the process with the cause's sentence, fix and exit status (src/trajectories/_shared/running/failure-report.mjs).
trajectories.ncbr-auditnode src/trajectories/ncbr/pangram_audit_new_wniosek.mjs3Extract the written answers of the selected sections of an NCBR application draft and read Pangram's analysis of each, never writing to LSI2.
secrets.acquired-writeevery credential a run acquires, resets or adopts (writeWelesAcquiredSecret)14Write one credential a run acquired, reset or adopted into the one vault item its acquisition contract names, after checking the contract, the value, the request and the origin.
secrets.acquired-readevery read of a scoped role field or a workload-acquired field (readScopedField, readAcquiredField)13Read one scoped credential field: a role's field with the consumer's own grant through Stado, or a field the run's workload identity acquires from Skarbiec through the acquisition helper.
secrets.acquisition-jobPOST /api/v1/credential-operations (acquireSecret, buildSecretAcquisitionPlan)4Build the job a worker runs to acquire, rotate or reset one credential: its objective, its identity and the constraints naming the vault item.
secrets.operation-answera credential operation run stating what it did (writeCredentialOperation), the worker answering the operation from it2Read what a credential operation's run states it did to the credential, from the one file and member it writes.
secrets.semantic-scholar-followupthe semanticscholar_key_followup action (trajectories/semanticscholar/key_followup.mjs)3Read the mailbox of a Semantic Scholar key request again until the key mail arrives, and store the first key Semantic Scholar accepts.
design.export-requestweles design export --provider figma --request <export-request.json>11Read a design export request and the Figma inventory it names, before Git, the vault or Figma is asked.
design.export-checkoutthe operations that use it19Check the checkout a design export publishes into: the root of a repository on the named branch, one push URL, a committer, nothing uncommitted, and the remote branch at the same commit.
design.export-publishweles design export --provider figma --request <export-request.json>13Hold the checkout for one design export, swap its generated tree into the managed directory, commit only that directory, push it and read the remote branch back.
design.parseweles design parse --provider figma <document.json[.gz]> <summary.json> <nodes.json> [<vocabulary.json>]5Read a Figma document from its bytes and write its summary, node index and design vocabulary.
design.figma-exportweles design export --provider figma --request <export-request.json>13Ask Figma for each inventory file's document, source images and previews with the acquired token, and write them into the export's working tree.
trajectories.linkedin-proxythe operations that use it15Hold a LinkedIn registration to one dedicated ISP exit: asked for by provider pool, resolved to a live ISP record, and seen from the same address at every stage.
trajectories.linkedin-submitthe operations that use it7Submit one LinkedIn signup form step: click its enabled button, await the POST it sends and read its answer, keeping the request, answer and page beside a failure.
trajectories.linkedin-registerthe linkedin_register action (trajectories/linkedin/register.mjs)22Register a new LinkedIn account on a dedicated ISP exit: check the browser fingerprint, reach the signup form, submit it, confirm the mailed code and save the signed-in account, ending at any challenge.

accounts#

37 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
subscription-not-foundselecting the {provider} subscription Weles acts onthe vault holds no brama:subscription item of this provider carrying that brama:id: tag: it was never recorded, was retired, or the id is mistypedno brama:subscription item of {provider} carries id {subscription_id}; the vault lists {provider_count} of {provider}: {provider_ids}run `weles accounts list` for the subscriptions and logins the vault resolves and name one of them with --subscriptionnot_found, exit 1, HTTP 404tests/accounts/logins/login-account-failures.mjs::a_subscription_the_vault_does_not_hold_is_named
subscription-ambiguousselecting the {provider} subscription Weles acts onmore than one brama:subscription item of this provider carries that id, or no id was named and the provider has several, so Weles cannot tell which account to act on{count} brama:subscription items of {provider} match id {subscription_id}: {subscription_items}name exactly one subscription with --subscription <id>; when two items carry one brama:id: tag, retag the stale one with `stado credentials item retag`config, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::two_subscriptions_with_one_id_are_refused_naming_both
subscription-identity-missingresolving the login of subscription {subscription_item}the subscription records no account (no context.account_ref, brama:account: or brama:login: tag) and no single login of its provider identifies itsubscription {subscription_item} records no context.account_ref, brama:account: or brama:login: tag; logins of {provider}: {provider_login_items}; every login: {login_items}; {way_out}record the account on the subscription item as the observed sentence says (`brama subscription attribute`, or a brama:login:<login item> tag), then run the command againconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_subscription_naming_no_account_is_refused
login-missingresolving the login of subscription {subscription_item}no login item in the vault carries the account the subscription identifies, so there is nothing to sign it in withsubscription {subscription_item} identifies {account_ref}; none of the {logins_read} logins read carries that accountstore the account's login in the vault as a login item whose username is {account_ref}, then run the command againconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_subscription_whose_account_has_no_login_is_refused
login-ambiguousresolving the login of subscription {subscription_item}several login items carry the account and they hold different passwords or authenticators, so Weles cannot tell which one signs it insubscription {subscription_item} identifies {account_ref}; logins: {candidates}, holding {credential_count} different passwords and {authenticator_count} authenticatorskeep one login for {account_ref} and retire the others, or tag the subscription brama:login:<login item> to name the one that signs inconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::two_logins_of_one_account_that_disagree_are_refused
login-method-unsupportedresolving the login of subscription {subscription_item}the login declares no login method, or one Weles does not sign in with (google_sso, email_password, email_code)login {login_item} declares login_method {login_method}; declare it with `{declaration}`declare how the login signs in, in its context's login_method or a weles:login-method:<method> tag, as the observed sentence namesconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_login_without_a_login_method_is_refused
subscription-provider-unsupportedresolving the login of subscription {subscription_item}the subscription's brama:provider: tag names a provider Weles signs no subscription in for (claude, codex, kimi) although a sign-in route of the worker took itsubscription {subscription_item} carries brama:provider:{provider}; Weles signs in {supported}correct the subscription item's brama:provider: tag to the provider it belongs to, then ask for the sign-in againconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_subscription_of_a_provider_without_a_sign_in_is_refused
login-record-conflictreading what vault item {item} declares about its sign-inthe item declares {field} differently in two of the places it may be written (its context, a tag, its metadata, its username), and Weles does not let the first one that is not empty decideitem {item} declares {field} as {said}keep one value of {field} on item {item}: correct or remove the stale place the observed sentence namesconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_login_whose_method_disagrees_with_its_tag_is_refused
login-record-unreadablereading what vault item {item} declares about its sign-inthe item holds {field} that is not JSON where Weles reads the login's metadata from it{field} of item {item} holds {length} characters that do not parse as JSON ({error}); the value is not shown, it may hold a grantrewrite {field} of item {item} as one JSON document, or move the secret it holds into the field of its own name (password, totp_secret)config, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_login_whose_value_is_not_json_is_refused
subscription-source-cyclefollowing the source items of subscription {subscription_item}the items its context.source_item names lead back to an item already read, so no login is ever reacheda cyclic source reference: {path} leads back to {source_item}point context.source_item of {source_item} at the item that holds the login, or record the account on the subscription itselfconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_subscription_whose_sources_loop_is_refused
subscription-source-missingfollowing the source items of subscription {subscription_item}its context.source_item names an item the vault does not hold: it was retired or renamedthe sources {path} end at {source_item}, which the vault lists under no id or item_uidpoint context.source_item at an item the vault holds, or record the account on the subscription itselfconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_subscription_naming_a_missing_source_is_refused
login-item-not-foundreading how login {login_item} signs inthe vault holds no login item with that id or item_uidthe vault lists {login_count} login items; none has id or item_uid {login_item}run `weles accounts list` for the subscriptions and logins the vault resolves, and name a login item it showsnot_found, exit 1, HTTP 404tests/accounts/logins/login-account-failures.mjs::an_authenticator_enrolment_for_a_login_the_vault_lacks_is_refused
login-fields-missingreading the sign-in material of login {login_item}the login item holds no fields at all, so it has no username or password to sign in withlogin {login_item} of subscription {subscription_id} is a document of {members} with no fieldsstore the username and password on login {login_item}, then ask for the sign-in againconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_sign_in_whose_login_lost_its_fields_is_refused
login-identity-changedreading the sign-in material of login {login_item}the login's username no longer names the account resolved when the sign-in was admitted: it was rewritten while the run startedlogin {login_item} now names {now}; the sign-in was admitted for {account_ref}ask for the sign-in again, so the account is resolved from the login as it stands nowconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_sign_in_whose_login_changed_account_is_refused
login-password-missingreading the sign-in material of login {login_item}the login declares a method that signs in with a password, and holds nonelogin {login_item} signs in by {login_method}; its password field is {state}store the password on login {login_item}, or declare the method it really signs in withconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_password_sign_in_whose_login_holds_no_password_is_refused
subscription-changedkeeping the grant a sign-in earned on subscription {subscription_item}the subscription or one of its login items changed in the vault while the sign-in ran, so the grant may belong to another account and is not writtenthe account revision was {admitted} at admission and is {current} now; the existing grant was not overwrittenrun `weles accounts refresh --provider <provider> --subscription {subscription_id}` again; it resolves the account as it stands nowconfig, exit 1, HTTP 503tests/accounts/logins/login-account-failures.mjs::a_grant_for_a_subscription_that_changed_meanwhile_is_not_written
grant-unconfirmedkeeping the grant a sign-in earned on subscription {subscription_item}the vault accepted the write and then returned another value: another writer replaced it, or the vault lost the write{written} characters were written to fields.value of {subscription_item}, and the vault returned {found}run `weles accounts refresh --provider <provider> --subscription {subscription_id}` again once the vault answersinfra_down, exit 69, HTTP 503, retryabletests/accounts/logins/login-account-failures.mjs::a_grant_the_vault_does_not_return_is_named
refresh-unfinishedrefreshing the sign-in of {provider} subscription {subscription}the executor admitted the sign-in and its answer ended before the run's result line: the Weles API restarted or the connection broke while the run went onthe answer of {endpoint} ended after {events} events; the last: {last}run `weles runs list` to see whether the sign-in still runs; run the same `weles accounts refresh` again, which joins a run still under wayinfra_down, exit 69, HTTP 503, retryabletests/accounts/sign-in-failures.mjs::a_refresh_whose_answer_ends_before_its_result_is_named
refresh-failedrefreshing the sign-in of {provider} subscription {subscription}the sign-in ran on the executor and ended without a new grant: the provider refused the login, asked for a step nobody answered, or the run failedrun {run}: {error}: {message}run `weles runs show {run}` for what the run saw, answer what it asks for, then run `weles accounts refresh --provider {provider} --subscription {subscription}` againrefused, exit 1, HTTP 403tests/accounts/sign-in-failures.mjs::a_refresh_the_provider_refuses_names_its_run
refresh-unavailablerefreshing the sign-in of {provider} subscription {subscription}the sign-in did not get to sign the account in, for a cause the run states asking again can change: its browser host, its browser or the provider's OAuth endpoint was not reachedrun {run}: {error}: {message}run `weles runs show {run}` for the step it stopped at; run the same `weles accounts refresh` again once that host or endpoint answersinfra_down, exit 69, HTTP 503, retryabletests/accounts/sign-in-failures.mjs::a_refresh_that_did_not_reach_the_provider_is_retryable
sign-out-unconfirmedsigning {provider} subscription {subscription} outthe vault accepted the item without its grant and then returned the item with a grant again: another writer (a sign-in that just finished) wrote one meanwhileitem {item} still holds a grant after the writerun `weles runs list` for a sign-in of this account that is under way, cancel it with `weles runs cancel`, then run `weles accounts logout` againinfra_down, exit 69, HTTP 503, retryabletests/accounts/sign-in-failures.mjs::a_sign_out_a_sign_in_overwrites_is_named
session-action-unsetrestoring the session of the {platform} account {account} for {script}ACTION is not set, and the account session reads the run's network requirements by the action it performsACTION {value}; script {script}run it through the Weles worker, which sets ACTION for every run it starts, or set ACTION to the action it performsconfig, exit 1, HTTP 503tests/accounts/logins/session-failures.mjs::a_session_whose_run_names_no_action_is_refused
session-proxy-type-unstatedresolving the proxy {action} of the {platform} account {account} browses throughthe run needs a proxy ({reason}) and its network names no proxy type to resolve, and the account has no pinned exitproxy type: none; country {country}; PROXY_URL unset; WELES_ALLOW_DIRECT_ACCOUNT_SESSION unsetname the proxy type of the run (its network requirements), set PROXY_URL to an exit, or pin one to the accountconfig, exit 1, HTTP 503tests/accounts/logins/session-failures.mjs::a_session_whose_network_names_no_proxy_type_is_refused
session-proxy-unavailableresolving the proxy {action} of the {platform} account {account} browses throughno provider able to serve {action} resolved a {type} exit in {country}, so the browser is not launched without oneproviders tried: {tried}; {why}run again once a provider resolves a {type} exit in {country} (the observed names the providers whose standing is failing or unpriced), or pin an exit to the accountinfra_down, exit 69, HTTP 503, retryabletests/accounts/logins/session-failures.mjs::a_session_no_provider_resolves_is_refused
session-exit-unparsableresolving the proxy {action} of the {platform} account {account} browses throughthe {provider} exit resolved for the account has a server address that is no URL, so no host, port or protocol can be pinned from itserver of {length} characters; the parser said: {problem}; nothing was pinnedcorrect the {provider} source's server form in src/proxy/sources/, then run the session againunknown, exit 1, HTTP 500tests/accounts/logins/session-failures.mjs::a_session_whose_resolved_exit_is_no_url_is_refused
pinned-address-unparsablereading the proxy pinned to the {platform} account {account} for {action}the pin's {field} is no URL, so no host, port or protocol can be read from it{field} of {length} characters; the parser said: {problem}; the value is not shown, it may carry the proxy's passwordwrite the pin's {field} as <protocol>://<host>:<port> in metadata_json.proxy of the account's Skarbiec record, or retire the accountconfig, exit 1, HTTP 503tests/accounts/pinned-failures.mjs::a_pin_whose_address_is_no_url_is_refused
pinned-protocol-unstatedreading the proxy pinned to the {platform} account {account} for {action}the pin {host}:{port} names no protocol, so the proxy cannot be asked in the scheme it servespin members: {members}state protocol (http or socks5) in metadata_json.proxy of the account's Skarbiec record, or retire the accountconfig, exit 1, HTTP 503tests/accounts/pinned-failures.mjs::a_pin_without_a_protocol_is_refused
pinned-burnedreading the proxy pinned to the {platform} account {account} for {action}the pinned host {host} is in the burned_proxies setting for {platform}: the platform banned it, so the account cannot browse from it and is not moved to another exitburned_proxies holds {host} for {platform}; port {port}retire the account, or remove {host} from the burned_proxies Weles setting in Skarbiec once the platform lifted the banrefused, exit 1, HTTP 403tests/accounts/pinned-failures.mjs::a_pin_on_a_burned_host_is_refused
pinned-pool-retiredreading the proxy pinned to the {platform} account {account} for {action}the pinned exit {host}:{port} belongs to a retired pool ({retired}); the account was marked inactive with retired_reason {reason}retired_proxy_pools names it: {retired}register a new account for {platform}: an account keeps its one exit, and this one is retiredrefused, exit 1, HTTP 403tests/accounts/pinned-failures.mjs::a_pin_in_a_retired_pool_retires_the_account
pinned-provider-unknownreading the proxy pinned to the {platform} account {account} for {action}the pin {host}:{port} names no provider and its host is no provider's, so it cannot be rebuilt; the account was marked inactive with retired_reason {reason}provider: none; host {host}, which src/proxy/policy.ts providerFromHost gives no providerregister a new account for {platform}, or state the provider in the retired account's pin and mark it active againrefused, exit 1, HTTP 403tests/accounts/pinned-failures.mjs::a_pin_of_no_provider_retires_the_account
pinned-capability-failingreading the proxy pinned to the {platform} account {account} for {action}the capability matrix marks {provider} failing for {action}, so the account's pinned exit is not used for itproxy_capability_matrix: {provider} x {action} = fail; pin {host}:{port}run the capability probe for {provider} again once the provider serves {action}; the matrix decides from its resultrefused, exit 1, HTTP 403tests/accounts/pinned-failures.mjs::a_pin_whose_provider_fails_the_action_is_refused
pinned-record-write-refusedwriting {change} to the Skarbiec account record {id} of {account}the write failed with a {kind} that no layer of the vault declares: every refusal of Skarbiec and of the secrets alternative is declared, so this one is a defect of this release, and the account record still holds what it held before{kind} at the write of {id}: {problem}; nothing was writtenrun the session again; when it repeats, report the error above with `weles version` (a release whose vault layer declares it will name the cause)unknown, exit 1, HTTP 500tests/accounts/pinned-failures.mjs::a_record_write_skarbiec_refuses_is_named
pinned-record-absentwriting {change} to the Skarbiec account record {id} of {account}Skarbiec holds no live account record {id}: it was deleted or retired after the session read itno item tagged weles:record:account has id {id}read the account again (`weles records adopt` tags records Skarbiec holds untagged) and start the session from the record Skarbiec holdsnot_found, exit 1, HTTP 404tests/accounts/pinned-failures.mjs::a_record_skarbiec_no_longer_holds_is_named
social-bindings-conflictingchoosing the {platform} account this run signs in withWELES_LOGIN_ITEM, ACCOUNT_ITEM and ACCOUNT_ID name {count} different accounts, and a run signs in with oneWELES_LOGIN_ITEM {login}; ACCOUNT_ITEM {item}; ACCOUNT_ID {id}; no account record was readstart the run bound to one account: set only one of WELES_LOGIN_ITEM, ACCOUNT_ITEM and ACCOUNT_ID, or the same item in each (the Weles worker sets them from the run request)config, exit 1, HTTP 503tests/accounts/logins/social-failures.mjs::a_run_bound_to_two_accounts_is_refused
stale-account-absentmarking the cookies of account {account} stale and starting its re-loginthe vault holds no active account record {account}: it was retired or deleted after the run read it, or the run was bound to a mistyped idthe account record {account} {state}; nothing was marked and no login run was submittedbind the next run to an active account record (`stado capabilities resolve secrets --consumer weles` names the vault the account records are read from), or record the account againnot_found, exit 1, HTTP 404tests/accounts/logins/social-failures.mjs::a_stale_mark_on_an_absent_account_is_refused
acquired-item-existsrecording the {provider} account {email} bought by acquisition {request}the vault already holds item {item}, so recording this account would overwrite another record of the same addressitems already held: {held}; subscription id {subscription}; nothing was written`weles accounts list --provider {provider}` shows the subscription already recorded for {email}; sign that one in instead of buying the address again, or retire the old items firstrefused, exit 1, HTTP 403tests/accounts/acquired-failures.mjs::an_account_whose_items_exist_is_not_overwritten
acquired-item-unconfirmedrecording the {provider} account {email} bought by acquisition {request}the vault took the write of {item} and returned it without its acquired_at: another writer replaced it, or the vault lost the writeitem {item} read back: {found}; the login row {login} and the subscription item {subscription_item} were both written`stado credentials get {item}` (on the vault Stado names) shows the item as the vault holds it; write the acquisition record again once the vault keeps its writesinfra_down, exit 69, HTTP 503, retryabletests/accounts/acquired-failures.mjs::an_account_the_vault_does_not_return_is_named

mail#

11 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
mail-alternative-unansweredresolving the mail family for weles, to {purpose}Stado names no mail alternative that answers: {why}`{command}` exited {status}; Stado cause {stado_cause}: {answer}; Stado fix: {stado_fix}install the skrzynka program where Stado looks for it (its PATH, or ~/.local/bin of the worker's HOME), or repair what Stado names; `stado capabilities resolve mail --consumer weles --json` shows the alternative Stado namesinfra_down, exit 69, HTTP 503, retryabletests/mail/alternative-failures.mjs::a_mail_family_no_program_answers_is_named
mail-alternative-otherresolving the mail family for weles, to {purpose}the alternative Stado named is not the Skrzynka program Weles runs: it expected provider skrzynka of kind program at an absolute pathprovider {provider}, kind {kind}, route {route}put skrzynka first in the mail order (`stado capabilities select mail --order skrzynka`); `stado capabilities resolve mail --consumer weles --json` shows the alternative Stado namesconfig, exit 1, HTTP 503tests/mail/alternative-failures.mjs::a_mail_alternative_that_is_no_program_is_named
skrzynka-unrunrunning Skrzynka to {purpose}the Skrzynka program Stado named could not be started ({errno}): it was removed or lost its execute permission after Stado proved it`{command}` in {directory}: {problem}reinstall skrzynka at {program}, or let Stado prove another; `stado capabilities resolve mail --consumer weles --json` shows the alternative Stado namesinfra_down, exit 69, HTTP 503, retryabletests/mail/inbox-failures.mjs::an_inbox_program_that_cannot_start_is_named
skrzynka-unavailablerunning Skrzynka to {purpose}Skrzynka could not reach what it reads the mail from (it calls its refusal {skrzynka_code} and says it may pass)`{command}` in {directory} exited {status}; Skrzynka said: {said}`skrzynka --organization {organization} status` names the database and what Skrzynka cannot reach; run again once it answersinfra_down, exit 69, HTTP 503, retryabletests/mail/inbox-failures.mjs::an_inbox_skrzynka_cannot_read_is_named
skrzynka-refusedrunning Skrzynka to {purpose}Skrzynka refused the command ({skrzynka_code}) and says retrying will not change it`{command}` in {directory} exited {status}; Skrzynka said: {said}repair what Skrzynka names (`skrzynka {verb} --help` shows what the command takes), then run againunknown, exit 1, HTTP 500tests/mail/inbox-failures.mjs::an_inbox_listing_skrzynka_refuses_is_named
skrzynka-not-jsonrunning Skrzynka to {purpose}Skrzynka ended successfully and printed no JSON: the program Stado named is another release, or one started with --text`{command}`: {bytes} bytes; the parser said: {problem}`{program} --version` names the release; install a skrzynka whose answers are JSON; `stado capabilities resolve mail --consumer weles --json` shows the alternative Stado namesunknown, exit 1, HTTP 500tests/mail/inbox-failures.mjs::an_inbox_answer_that_is_not_json_is_named
inbox-organization-unsetreading the mail Skrzynka holds for {recipient} from {sender}WELES_SKRZYNKA_ORGANIZATION names no Skrzynka organization, so the mail to {recipient} cannot be read: Skrzynka files every mailbox under oneWELES_SKRZYNKA_ORGANIZATION {value}; Stado was not asked and Skrzynka not runset WELES_SKRZYNKA_ORGANIZATION in the Weles service's environment (`stado service env set weles`) to the organization the mailbox of {recipient} is declared inconfig, exit 1, HTTP 503tests/mail/inbox-failures.mjs::an_inbox_without_its_organization_is_refused
inbox-list-shapereading the mail Skrzynka holds for {recipient} from {sender}Skrzynka printed JSON that is no list of messages with id, sender, recipients, subject, received_at and body_text: another release of Skrzynka answered`{command}`: {found}`{program} --version` names the release; install the skrzynka whose message list Weles readsunknown, exit 1, HTTP 500tests/mail/inbox-failures.mjs::an_inbox_answer_of_another_shape_is_named
domain-record-shapereading the inbound mail domains recorded in the Weles setting inbound_email_domainsthe setting holds {type}, not the list of domain rows Weles keeps there, so no domain is picked from it and it is not overwritten{type} of {length} characters, beginning {head}move the setting inbound_email_domains aside in the vault (it holds something else) so Weles records the domains again, or store a list of {domain, status, signup_count} rowsconfig, exit 1, HTTP 503tests/mail/domain-failures.mjs::a_domain_record_that_is_no_list_is_refused
domain-unstatedchoosing the inbound mail domain of a new {platform} accountno inbound domain is recorded and none of FORCE_EMAIL_DOMAIN, AGENT_EMAIL_DOMAINS or AGENT_DOMAIN is set; no domain is assumedinbound_email_domains holds {rows} rows; FORCE_EMAIL_DOMAIN {forced}; AGENT_EMAIL_DOMAINS {listed}; AGENT_DOMAIN {single}set AGENT_DOMAIN (or AGENT_EMAIL_DOMAINS, comma-separated) to a domain whose mail Skrzynka receives, in the Weles service environment (`stado service env set weles`)config, exit 1, HTTP 503tests/mail/domain-failures.mjs::a_pick_with_no_domain_stated_is_refused
domain-unavailablechoosing the inbound mail domain of a new {platform} accountevery inbound domain recorded is broken or blocked for {platform}: no active domain has a mail exchanger and no block by {platform}{domains}; the rows were written back with the status foundrecord a new inbound domain whose MX record points at the receiving provider, or repair the MX of one listed (`dig MX <domain>` shows it); a domain {platform} blocked stays blocked for itrefused, exit 1, HTTP 403tests/mail/domain-failures.mjs::a_pick_when_every_domain_is_blocked_is_refused

proxy#

31 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
pin-provider-unstatedrebuilding the proxy {host}:{port} pinned to the {platform} account {account} for {action}the pin names no provider and its host is no provider Weles knows, so no provider secret can rebuild its credentialsprovider: none; host {host}, which src/proxy/policy.ts providerFromHost gives no providerstate provider in the account's pin (metadata_json.proxy of its Skarbiec account record), or retire the accountconfig, exit 1, HTTP 503tests/proxy/pin-failures.mjs::a_pin_naming_no_provider_is_refused
pin-type-unstatedrebuilding the proxy {host}:{port} pinned to the {platform} account {account} for {action}the pin states {kind} as its pool type, which is none of isp, mobile or residential, so its credentials cannot be chosenproxy_type {kind}; provider {provider}state proxy_type (isp, mobile or residential) in the account's pin (metadata_json.proxy of its Skarbiec account record), or retire the accountconfig, exit 1, HTTP 503tests/proxy/pin-failures.mjs::a_pin_naming_no_pool_type_is_refused
pin-secret-undeclaredrebuilding the proxy {host}:{port} pinned to the {platform} account {account} for {action}Weles declares no scoped secret holding the credentials of {provider} {type} proxies, and the pin carries none of its ownprovider {provider}, pool {type}; credential_ref {reference}pin the account to a provider Weles holds credentials for (src/proxy/sources/provider_credentials.ts secretServiceFor), or give the pin a credential_ref of its ownconfig, exit 1, HTTP 503tests/proxy/pin-failures.mjs::a_pin_whose_provider_has_no_secret_is_refused
pin-secret-unreadrebuilding the proxy {host}:{port} pinned to the {platform} account {account} for {action}the scoped secret {secret} holding {provider}'s credentials gave no {missing}, so the proxy cannot be authenticatedsecret {secret}: username {username}, password {password}; the values are not shownstore username and password on the item the scoped secret {secret} names in Skarbiec, then start the session againconfig, exit 1, HTTP 503tests/proxy/pin-failures.mjs::a_pin_whose_secret_lacks_a_field_is_refused
pin-sticky-session-unstatedrebuilding the proxy {host}:{port} pinned to the {platform} account {account} for {action}the pin is a {type} exit and states no sticky_session_id, so the session it was pinned in cannot be asked for againproxy_type {type}; sticky_session_id absent; country {country}state sticky_session_id in the account's pin (metadata_json.proxy of its Skarbiec account record), or retire the accountconfig, exit 1, HTTP 503tests/proxy/pin-failures.mjs::a_sticky_pin_without_its_session_is_refused
pin-country-unstatedrebuilding the proxy {host}:{port} pinned to the {platform} account {account} for {action}the pin is a {type} exit and states no country, so the sticky session would be asked for in no country it was pinned inproxy_type {type}; sticky_session_id present; country absentstate country in the account's pin (metadata_json.proxy of its Skarbiec account record), or retire the accountconfig, exit 1, HTTP 503tests/proxy/pin-failures.mjs::a_sticky_pin_without_its_country_is_refused
pin-address-absentopening a CONNECT tunnel to {target}:{targetPort} through the proxy {host}:{port} pinned to the {platform} account {account}the rebuilt pin names no proxy host and port to ask; the account keeps its one exit, so the session does not start on anotherhost {host}, port {port}state host and port in the account's pin (metadata_json.proxy of its Skarbiec account record), or retire the accountconfig, exit 1, HTTP 503tests/proxy/pin-failures.mjs::a_pin_without_an_address_is_refused
pin-runtime-port-unknownopening a CONNECT tunnel to {target}:{targetPort} through the proxy {host}:{port} pinned to the {platform} account {account}this Node's HTTPS agent names no default port, so the tunnel has no port to ask the proxy fornode {node}; https.globalAgent.defaultPort is {kind}run Weles on the Node release its package.json engines name (`node --version` shows this one)config, exit 1, HTTP 503tests/proxy/pin-failures.mjs::a_node_without_an_https_port_is_named
pin-tunnel-unauthenticatedopening a CONNECT tunnel to {target}:{targetPort} through the proxy {host}:{port} pinned to the {platform} account {account}the proxy refused the credentials of the pin (HTTP {status}): the provider's password changed, or the account's sticky session ended; the account keeps its one exit, so the session does not start on anotherCONNECT answered {status} {message}; credentials {sent}store the provider's current username and password on the item of its scoped secret in Skarbiec, or retire the account when its session endedauth, exit 1, HTTP 401tests/proxy/pin-failures.mjs::a_pin_whose_credentials_the_proxy_refuses_is_named
pin-tunnel-refusedopening a CONNECT tunnel to {target}:{targetPort} through the proxy {host}:{port} pinned to the {platform} account {account}the proxy answered the CONNECT with HTTP {status} instead of 200: it will not reach the platform from this exit; the account keeps its one exit, so the session does not start on anotherCONNECT answered {status} {message}read the provider's dashboard for why the exit refuses the platform; retire the account when the exit is gonerefused, exit 1, HTTP 403tests/proxy/pin-failures.mjs::a_pin_whose_proxy_refuses_the_tunnel_is_named
pin-tunnel-unresolvedopening a CONNECT tunnel to {target}:{targetPort} through the proxy {host}:{port} pinned to the {platform} account {account}the proxy's host name did not resolve ({errno}): the provider retired the name, or this host's resolver is down; the account keeps its one exit, so the session does not start on another{errno}: {problem}`dig {host}` shows whether the name resolves; run again once it does, or retire the account when the provider retired itinfra_down, exit 69, HTTP 503, retryabletests/proxy/pin-failures.mjs::a_pin_whose_proxy_name_does_not_resolve_is_named
pin-tunnel-connection-refusedopening a CONNECT tunnel to {target}:{targetPort} through the proxy {host}:{port} pinned to the {platform} account {account}nothing accepts connections at the proxy's address (ECONNREFUSED): the provider moved the exit or it is down; the account keeps its one exit, so the session does not start on another{errno}: {problem}`nc -vz {host} {port}` shows whether the exit listens; run again once it does, or retire the account when it is goneinfra_down, exit 69, HTTP 503, retryabletests/proxy/pin-failures.mjs::a_pin_whose_proxy_refuses_connections_is_named
pin-tunnel-brokenopening a CONNECT tunnel to {target}:{targetPort} through the proxy {host}:{port} pinned to the {platform} account {account}the connection to the proxy broke before it answered the CONNECT ({errno}): the network between, or the exit, dropped it; the account keeps its one exit, so the session does not start on another{errno}: {problem}run again; when it repeats, `nc -vz {host} {port}` shows whether the exit answers from this hostinfra_down, exit 69, HTTP 503, retryabletests/proxy/pin-failures.mjs::a_pin_whose_connection_breaks_is_named
exit-geography-unreachedreading where {subject} is from {service}the geography lookup did not answer, so the exit has no country a persona could follow{problem}run again once {service} answers from this host (`curl -s {service}` from this host shows what it answers)infra_down, exit 69, HTTP 503, retryabletests/proxy/exits/exit-geography-failures.mjs::a_lookup_that_does_not_answer_is_named
exit-geography-unreadablereading where {subject} is from {service}the lookup answered HTTP {status} with a body that is not JSON{bytes} characters, beginning {head}run again once {service} answers its JSON document (`curl -s {service}` from this host shows what it answers)unknown, exit 1, HTTP 500tests/proxy/exits/exit-geography-failures.mjs::a_lookup_answer_that_is_not_json_is_named
exit-geography-refusedreading where {subject} is from {service}the lookup answered HTTP {status} with status {answer}, so it placed the address nowhereits message: {message}for a proxy exit, resolve another exit; for a session without a proxy, run it on a host whose public address the lookup places, or start it with a proxy whose exit it placesunknown, exit 1, HTTP 500tests/proxy/exits/exit-geography-failures.mjs::an_address_the_lookup_cannot_place_is_named
exit-geography-unplacedreading where {subject} is from {service}the lookup answered success but named no country codethe fields it answered: {fields}run again once {service} names the country of the address (`curl -s {service}` from this host shows what it answers)unknown, exit 1, HTTP 500tests/proxy/exits/exit-geography-failures.mjs::a_lookup_answer_without_a_country_is_named
public-address-service-unsetreading which service tells this host its public addressWELES_PUBLIC_ADDRESS_URL is {state}, and no address service is assumedWELES_PUBLIC_ADDRESS_URL {state}set WELES_PUBLIC_ADDRESS_URL to the https:// address of a service that answers the caller's address as plain text, with no user, password or fragmentconfig, exit 1, HTTP 503tests/proxy/exits/public-address-failures.mjs::an_unset_address_service_is_refused
public-address-service-invalidreading which service tells this host its public addressWELES_PUBLIC_ADDRESS_URL {problem}WELES_PUBLIC_ADDRESS_URL of {length} characters; scheme {scheme}; the value is not shown, it may carry a passwordset WELES_PUBLIC_ADDRESS_URL to the https:// address of a service that answers the caller's address as plain text, with no user, password or fragmentconfig, exit 1, HTTP 503tests/proxy/exits/public-address-failures.mjs::an_address_service_that_is_no_https_url_is_refused
public-address-answer-not-ipreading the public address {service} answeredthe answer is not one IP address as plain text: the service answers a page, or another format{bytes} characters, beginning {head}point WELES_PUBLIC_ADDRESS_URL at a service that answers only the caller's address (`curl -s {service}` shows what it answers)unknown, exit 1, HTTP 500tests/proxy/exits/public-address-failures.mjs::an_address_answer_that_is_no_ip_is_named
registry-unreachedreading the IANA {family} special-purpose registry {address}the registry could not be fetched: the name did not resolve, the connection was refused or broke, or a proxy refused it{answer}check that this host reaches https://www.iana.org (`curl -sI {address}`), then run againinfra_down, exit 69, HTTP 503, retryabletests/proxy/exits/addresses-failures.mjs::a_registry_that_cannot_be_fetched_is_named
registry-failingreading the IANA {family} special-purpose registry {address}IANA answered HTTP {status}, a failure or a limit on its side, so the registry is not readHTTP {status} {statusText}run again later; IANA answers its registries again once it recoversinfra_down, exit 69, HTTP 503, retryabletests/proxy/exits/addresses-failures.mjs::a_registry_iana_fails_to_serve_is_named
registry-refusedreading the IANA {family} special-purpose registry {address}IANA answered HTTP {status} for the registry address, so it no longer serves the registry thereHTTP {status} {statusText}find the registry's current CSV address at https://www.iana.org/assignments and update REGISTRY_CSV; the next judgement reads the registries again; if IANA moved or reformatted them, the reader in src/proxy/quality/special-addresses.ts needs the new formconfig, exit 1, HTTP 503tests/proxy/exits/addresses-failures.mjs::a_registry_address_iana_does_not_serve_is_named
registry-answer-unreadreading the IANA {family} special-purpose registry {address}the registry answer broke off while its body was readHTTP {status}; {answer}run again; the answer is read whole or not at allinfra_down, exit 69, HTTP 503, retryabletests/proxy/exits/addresses-failures.mjs::a_registry_answer_cut_off_is_named
registry-emptyreading the IANA {family} special-purpose registry {address}the registry answered no header line, so there is no column to read{bytes} bytes of blank linesthe next judgement reads the registries again; if IANA moved or reformatted them, the reader in src/proxy/quality/special-addresses.ts needs the new formunknown, exit 1, HTTP 500tests/proxy/exits/addresses-failures.mjs::an_empty_registry_is_named
registry-column-absentreading the IANA {family} special-purpose registry {address}the registry has no "{column}" column, which the reader needs to judge an addressheader: {header}the next judgement reads the registries again; if IANA moved or reformatted them, the reader in src/proxy/quality/special-addresses.ts needs the new formunknown, exit 1, HTTP 500tests/proxy/exits/addresses-failures.mjs::a_registry_without_its_columns_is_named
registry-prefix-invalidreading the IANA {family} special-purpose registry {address}the registry lists "{prefix}" ({name}), which is not an address prefix of the form network/lengthblock "{prefix}" named {name}the next judgement reads the registries again; if IANA moved or reformatted them, the reader in src/proxy/quality/special-addresses.ts needs the new formunknown, exit 1, HTTP 500tests/proxy/exits/addresses-failures.mjs::a_registry_block_that_is_no_prefix_is_named
registry-blocks-nonereading the IANA {family} special-purpose registry {address}the registry lists no special-purpose blocks, so no address could be judged{records} records under header {header}the next judgement reads the registries again; if IANA moved or reformatted them, the reader in src/proxy/quality/special-addresses.ts needs the new formunknown, exit 1, HTTP 500tests/proxy/exits/addresses-failures.mjs::a_registry_without_blocks_is_named
registries-unreadjudging whether {address} is publicthe IANA special-purpose registries have not been read in this process (loadSpecialAddresses), so the address is refused rather than guessed; a defect of the calleraddress {address}; registries unreadreport the caller: it must await loadSpecialAddresses() before judging an addressunknown, exit 1, HTTP 500tests/proxy/exits/addresses-failures.mjs::an_address_judged_before_the_registries_are_read_is_refused
address-not-ipjudging whether {address} is public{address} is not an IP address, so no registry block can hold itaddress "{address}"resolve the name to its addresses first and judge each of themrefused, exit 1, HTTP 403tests/proxy/exits/addresses-failures.mjs::text_that_is_no_address_is_refused
address-not-publicjudging whether {address} is publicnon-public network address denied: {address} is in {prefix} ({name}), which IANA does not declare globally reachable{address} in {prefix} ({name})reach the target on a public address; a private, loopback, link-local or documentation address is never admittedrefused, exit 1, HTTP 403tests/proxy/exits/addresses-failures.mjs::a_private_address_is_refused_naming_its_block

trajectories#

133 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
parp-organization-unsetreading the PARP reset mail of {email} from SkrzynkaWELES_SKRZYNKA_ORGANIZATION names no Skrzynka organization, and Skrzynka files the PARP mailbox under oneWELES_SKRZYNKA_ORGANIZATION {value}; no browser was openedset WELES_SKRZYNKA_ORGANIZATION to the organization the mailbox of {email} is declared in (`stado service env set weles`), then run againconfig, exit 1, HTTP 503tests/trajectories/parp_ncbr/parp-login-failures.mjs::a_parp_login_without_an_organization_is_refused
parp-account-otherbinding the new PARP password of {email} to its vault itemthe run's credential constraints name another account than PARP_EMAIL, so the password would be kept as another account's loginPARP_EMAIL {email}; the constraints name {constrained} for item {item}; no browser was openedstart the run with PARP_EMAIL and the constraints' account_email naming the same PARP accountconfig, exit 1, HTTP 503tests/trajectories/parp_ncbr/parp-custody.mjs::a_reset_for_another_account_is_refused
parp-contract-otherbinding the new PARP password of {email} to its vault itemthe item the constraints name is no managed PARP password: its contract is set on another origin or is no passworditem {item}: field {field}, origin {origin}; a PARP password is field password on {expected}; no browser was openeddeclare {item} with provider parp in WELES_MANAGED_PASSWORD_CONTRACTS_FILE, or start the run for the item declared soconfig, exit 1, HTTP 503tests/trajectories/parp_ncbr/parp-custody.mjs::a_reset_into_an_item_of_another_provider_is_refused
parp-mailbox-absentreading the PARP reset mail of {email} from SkrzynkaSkrzynka declares no mailbox {email} in organization {organization}, so the reset mail cannot be read`{command}` listed {count} mailboxes: {emails}; the reset was already asked of PARPdeclare the mailbox from its Skarbiec item (`skrzynka --organization {organization} mailbox declare --skarbiec-item <item>`), then run againnot_found, exit 1, HTTP 404tests/trajectories/parp_ncbr/parp-login-failures.mjs::a_parp_mailbox_skrzynka_does_not_declare_is_named
parp-reset-unarrivedreading the PARP reset mail of {email} from Skrzynkano mail from {sender} received since {since} links below {host}: the reset mail has not arrived yet, or PARP held the reset (a captcha or a block){count} messages from {sender} in mailbox {mailbox} since {since}, none with a link below {host}run again once the reset mail arrives; the run's screenshots under its recordings (parp_<step>_*.png) show the page (reset_submitted)timeout, exit 69, HTTP 504, retryabletests/trajectories/parp_ncbr/parp-login-failures.mjs::a_reset_mail_that_has_not_arrived_is_named
parp-field-absentfilling {what} on {page}the page shows no visible field {what}: PARP changed its form, or another page opened in its placepage {page}; selector {selector} matches no visible fieldthe run's screenshots under its recordings (parp_<step>_*.png) show the page; correct the selector in src/trajectories/feng/auth/parp_login.mjs to the field the page showsunknown, exit 1, HTTP 500tests/trajectories/parp_ncbr/parp-login-failures.mjs::a_page_without_its_field_is_named
parp-record-unwrittenrecording where the new PARP password of {email} is keptthe reference record could not be written ({errno}): the recordings directory is absent or not writable; the password is already in vault item {item}{path}: {problem}make the recordings directory writable by the worker user (WELES_RECORDINGS_ROOT names it); the password is read from item {item}config, exit 1, HTTP 503tests/trajectories/parp_ncbr/parp-custody.mjs::a_record_that_cannot_be_written_is_named
publish-arguments-untakenreading the node src/trajectories/publish-requirements.mjs command lineit takes no argument: the file and the object are named by WELES_TRAJECTORY_REQUIREMENTS_FILE and WELES_TRAJECTORY_REQUIREMENTS_URIarguments: {given}run node src/trajectories/publish-requirements.mjs with no argumentrefused, exit 2, HTTP 403tests/trajectories/publish-requirements.mjs::an_argument_is_refused_before_anything_is_read
requirements-unreadablereading the trajectory requirements {path}the file cannot be read: it does not exist at that path, or this user may not read it{answer}name the declaration with WELES_TRAJECTORY_REQUIREMENTS_FILE, or run from a Weles tree that carries src/trajectories/requirements.jsonconfig, exit 1, HTTP 503tests/trajectories/publish-requirements.mjs::a_declaration_that_does_not_exist_is_named
requirements-not-jsonreading the trajectory requirements {path}the file is not one JSON documentthe parser said: {answer}correct {path} (src/trajectories/requirements.json, or the file WELES_TRAJECTORY_REQUIREMENTS_FILE names), then run it againconfig, exit 1, HTTP 503tests/trajectories/publish-requirements.mjs::a_declaration_that_is_not_json_is_named
requirements-schemareading the trajectory requirements {path}it declares another schema than {expected}, so its readers would read something elseschema: {schema}correct {path} (src/trajectories/requirements.json, or the file WELES_TRAJECTORY_REQUIREMENTS_FILE names), then run it againconfig, exit 1, HTTP 503tests/trajectories/publish-requirements.mjs::a_declaration_of_another_schema_is_refused
requirements-emptyreading the trajectory requirements {path}it names no trajectory: trajectories is absent, not an object, or emptytrajectories: {value}correct {path} (src/trajectories/requirements.json, or the file WELES_TRAJECTORY_REQUIREMENTS_FILE names), then run it againconfig, exit 1, HTTP 503tests/trajectories/publish-requirements.mjs::a_declaration_without_trajectories_is_refused
requirements-capabilities-not-listreading the trajectory requirements {path}a trajectory declares its capabilities as something other than a list{trajectory}: {value}correct {path} (src/trajectories/requirements.json, or the file WELES_TRAJECTORY_REQUIREMENTS_FILE names), then run it againconfig, exit 1, HTTP 503tests/trajectories/publish-requirements.mjs::a_trajectory_without_a_list_is_refused
requirements-capability-unknownreading the trajectory requirements {path}a trajectory names a capability no reader on the fleet knows, so publishing it would promise what nothing keeps{trajectory} declares {unknown}; the known capabilities are {known}correct {path} (src/trajectories/requirements.json, or the file WELES_TRAJECTORY_REQUIREMENTS_FILE names), then run it againconfig, exit 1, HTTP 503tests/trajectories/publish-requirements.mjs::an_unknown_capability_is_refused
requirements-not-read-backreading {uri} back after publishing itStado accepted the write and the object then reads back other bytes: another publisher wrote it in between, or the store did not keep the writelocal {local_bytes} bytes sha256 {local_digest}, published {remote_bytes} bytes sha256 {remote_digest}run it again; `stado storage stat {uri}` reports the object Stado holds nowinfra_down, exit 69, HTTP 503, retryabletests/trajectories/publish-requirements.mjs::a_publication_read_back_otherwise_is_named
input-unsetreading {names}: {what}none of these is set, and the run cannot know the value by itselfnone of {names} is setstate one of {names} when the run is started; nothing is assumed in its placerefused, exit 2, HTTP 403tests/trajectories/pages/inputs-failures.mjs::a_run_without_its_stated_text_is_refused
count-invalidreading {name}: {what}it is unset, or not a whole number above zero{name}: {value}state {name} when the run is started (the request parameter or environment variable of that name); nothing is assumed in its place, as a whole number above zerorefused, exit 2, HTTP 403tests/trajectories/pages/inputs-failures.mjs::a_count_that_is_no_whole_number_is_refused
budget-invalidreading {name}: {what}it is unset, or not a whole number of zero or more{name}: {value}state {name} when the run is started (the request parameter or environment variable of that name); nothing is assumed in its place, as a whole number of zero or morerefused, exit 2, HTTP 403tests/trajectories/pages/inputs-failures.mjs::a_negative_budget_is_refused
number-invalidreading {name}: {what}it is unset, or not a finite number{name}: {value}state {name} when the run is started (the request parameter or environment variable of that name); nothing is assumed in its place, as a numberrefused, exit 2, HTTP 403tests/trajectories/pages/inputs-failures.mjs::a_limit_that_is_no_number_is_refused
choice-invalidreading {names}: {what}the value is not one of the choices this trajectory knows{names}: "{value}"; the choices: {choices}state one of {choices} in {names}refused, exit 2, HTTP 403tests/trajectories/pages/inputs-failures.mjs::a_choice_the_trajectory_does_not_know_is_refused
json-invalidreading {name} as JSONit is set and does not parse as JSON{name}: {answer}state {name} as one JSON value, or leave it unset where the trajectory takes no valuerefused, exit 2, HTTP 403tests/trajectories/pages/inputs-failures.mjs::a_json_input_that_does_not_parse_is_refused
page-field-value-differswriting {what} on {url}after the text was typed the field holds other text: the page dropped or reformatted keystrokes, or a clear did not take and the old value stayedheld {observed} ({held} characters), typed {expected} characters; nothing was savedlook at the run recording at that step; when the page reformats the value (a mask, a counter), state the value in the form the page keepsrefused, exit 1, HTTP 403tests/trajectories/pages/page-failures.mjs::a_field_that_drops_keystrokes_is_named
page-field-absentwriting the stated {what} on {url}the page shows no such field, so the stated value would not be writtenno element matches {selector}leave the value unstated when this page has no such field, or open the page that has it; the run recording shows what the page heldnot_found, exit 1, HTTP 404tests/trajectories/pages/page-failures.mjs::a_stated_value_whose_field_is_absent_is_named
page-field-unfocusedtyping into the field {selector} on {url}the field did not take focus after a pointer click and a focus call, so every keystroke would go elsewhere: a control drawn over it took the clickthe focused element is {focused}look at the run recording at that step for what covers the field, and dismiss it before typingrefused, exit 1, HTTP 403tests/trajectories/pages/page-failures.mjs::a_field_that_never_takes_focus_is_named
page-control-missingtaking the {what} action once on {url}the page shows neither the control that takes it nor the one that undoes it: the page changed, or it is not the page the action is onneither {take} nor {taken} is visibleopen the page the action is on (the run recording shows the page it reached); when the site changed its controls, update the trajectorynot_found, exit 1, HTTP 404tests/trajectories/pages/page-failures.mjs::a_page_without_the_control_is_named
page-value-too-longfitting {what} into its field on {url}the value is longer than the field's own maxlength, and a value is written whole or not at all{length} characters; the field takes {max}shorten the stated value to {max} characters (the character's profile, or the run's input)refused, exit 2, HTTP 403tests/trajectories/pages/page-failures.mjs::a_value_longer_than_its_field_is_refused
page-row-unnamedfinding the row about {subject} among {rows} row(s) of the tablethe model answered neither a row number in range nor NONEit answered {answer}run it again; when the model keeps answering so, `stado capabilities resolve inference --consumer weles` shows which model Weles asksinfra_down, exit 69, HTTP 503, retryabletests/trajectories/pages/page-failures.mjs::a_model_that_names_no_row_is_named
page-control-unseenclicking the control "{description}" on {url}the vision model found no control matching the description on the settled pageno click target for "{description}"look at the run recording at that step: open the page that shows the control, or describe it as the page labels itnot_found, exit 1, HTTP 404tests/trajectories/pages/page-failures.mjs::a_control_the_model_does_not_see_is_named
page-closedreading the page during {operation}the page or its browser closed before the read finished: the run closed it, the operator did, or the browser endedlast address {url}run it again; when it recurs, the run log says what closed the page before this stepinfra_down, exit 69, HTTP 503, retryabletests/trajectories/pages/page-failures.mjs::a_closed_page_is_a_terminal_failure
page-crashedreading the page during {operation}the page's renderer crashed (out of memory, a browser fault, the site's own script)last address {url}run it again; when the same page keeps crashing, the run's browser log names the renderer's faultinfra_down, exit 69, HTTP 503, retryabletests/trajectories/pages/page-failures.mjs::a_page_that_crashes_is_named
page-request-failedwaiting for the answer to {request} after {operation} on {url}the browser reports the request failed before any answer: the connection was refused, reset or blocked, or the proxy refused it{answer}run it again; when it recurs, the browser's reason above and the run's network log name the address that refused it (the proxy, the site)infra_down, exit 69, HTTP 503, retryabletests/trajectories/pages/page-failures.mjs::a_request_that_fails_is_named
page-address-unparsableprinting a page address for the logthe address is no URL, even against the page it is relative to, so it is not printed (it may carry a secret){length} characters, relative to {base}look at the run recording at that step for the link the page heldrefused, exit 1, HTTP 403tests/trajectories/pages/page-failures.mjs::an_address_that_is_no_url_is_not_printed
overleaf-listing-incompletelisting the projects Overleaf's dashboard holdsthe dashboard's load-more control was pressed and the page settled with no more project rows than before, so the projects past the {rows} read are not listed, and a listing of {rows} would be taken for every project{rows} project rows; the control read {label}look at the run recording at the press: when the dashboard loaded its next projects late, run the listing again; when the control pressed is not the dashboard's load-more, the dashboard changed where it places itrefused, exit 1, HTTP 403tests/overleaf/dashboard-projects.mjs::a_press_that_adds_no_rows_is_refused
engagement-account-absentreading the active {platform} account for the {verb} runthe accounts store holds no active account of that platform: none was imported, or every one is marked banned or retiredno active {platform} account in {store}import or reactivate a {platform} account record in the accounts store; `stado credentials ls` lists the account records the store holdsnot_found, exit 1, HTTP 404tests/trajectories/engagement-failures.mjs::an_action_without_an_account_is_named
engagement-character-absentchoosing what {platform} account {account} writes for the {verb} runthe account has no character linked to speak as, and the run states no text of its ownaccount record {item} ({account}) holds neither metadata.character nor metadata.character_id; SVC_TEXT unset; no browser was startedstate SVC_TEXT with the text to post, or link a character to account record {item} (metadata.character_id); `stado credentials ls` lists the account records the store holdsrefused, exit 2, HTTP 403tests/trajectories/engagement-failures.mjs::an_action_without_a_character_or_text_is_refused
engagement-product-unnamedchoosing the product the {verb} run of {platform} promotes as account {account}the run names no PRODUCT_ID and the account's character promotes no productPRODUCT_ID unset; character {character} of account record {item} has no promoted_product_id; no browser was startedstate PRODUCT_ID, or give character {character} a promoted_product_idrefused, exit 2, HTTP 403tests/trajectories/engagement-failures.mjs::a_promotion_without_a_product_is_refused
engagement-product-unknownreading product {product} the {verb} run of {platform} promotes as account {account}the vault holds no product record of that idno live record of record_kind product whose item id or product_id is {product} in {store} (PRODUCT_ID {stated}); no browser was startedname a product the vault holds (PRODUCT_ID), or record product {product} first; `stado credentials ls` lists the account records the store holdsnot_found, exit 1, HTTP 404tests/trajectories/engagement-failures.mjs::a_promotion_of_an_unknown_product_is_named
engagement-ban-signalthe {verb} run of {platform} account {account}the platform's ban detector reads a restriction on the page after the run: the account is banned, challenged or limitedsignal {signal} after {label}; result {result}open the account's recording of this run (ban_signal.json beside it names the evidence); resolve the platform's challenge before the account acts againrefused, exit 1, HTTP 403tests/trajectories/engagement-failures.mjs::a_run_that_meets_a_ban_signal_is_named
engagement-recovery-unstartedstarting the recovery of {platform} account {account} after its probe read a checkpointthe recovery the checkpoint needs could not be started{answer} (snapshot {snapshot})correct what the recovery error names, then run the health probe againinfra_down, exit 69, HTTP 503, retryabletests/trajectories/engagement-failures.mjs::a_checkpoint_whose_recovery_cannot_start_is_named
engagement-health-unreadreading the health of {platform} account {account}the probe read neither a verdict of the ban detector nor a signed-in page: the page did not load, or the platform changed itsnapshot {snapshot}open the snapshot and the run recording; run the probe again, and update the detector when the platform changed its pageinfra_down, exit 69, HTTP 503, retryabletests/trajectories/engagement-failures.mjs::a_probe_that_reads_nothing_is_named
engagement-observation-unsetreading {name} of the declared observationit is unset: an observation runs only as admission resolves it from the parts of src/worker/deploy/weles-observation-declaration/{name}: {value}start the observation through the Weles API (`POST /run` with the observation), which states itrefused, exit 2, HTTP 403tests/trajectories/engagement-failures.mjs::an_observation_without_its_declaration_is_refused
engagement-scrolls-invalidreading GENERIC_OBSERVATION_SCROLLS of the declared observation {observation}it is not a whole number of screensGENERIC_OBSERVATION_SCROLLS: {value}state it as the whole number of screens the declaration givesrefused, exit 2, HTTP 403tests/trajectories/engagement-failures.mjs::an_observation_with_a_scroll_budget_that_is_no_number_is_refused
engagement-platform-unsupportedchoosing the ban detector of the observation {observation}Weles has no ban detector for that platform, so the run could not tell a ban from a pageplatform {platform}; detectors exist for {platforms}observe one of {platforms}refused, exit 2, HTTP 403tests/trajectories/engagement-failures.mjs::an_observation_of_a_platform_without_a_detector_is_refused
document-unsetreading the declared document this run fetchesthe run was started without the variable admission sets for it, so it was not started through generic_document_task{name} is {value}start the run as POST /run generic_document_task naming a declared document; a document trajectory cannot run on its ownconfig, exit 1, HTTP 503tests/trajectories/document-keep.mjs::a_keeper_started_without_admission_is_refused
document-download-faileddownloading document {document} from {origin}the browser reports the download of {file} did not complete{reason}open this run's recording to see where the site stopped the download, then run the document again; nothing was keptunknown, exit 1, HTTP 500tests/trajectories/document-keep.mjs::a_failed_download_is_named
document-emptychecking document {document} downloaded as {file}the site handed over a file with no bytes, so it holds no report however it is named{file}: 0 bytesopen this run's recording to see what the site showed for the report, then run the document again; nothing was keptunknown, exit 1, HTTP 500tests/trajectories/document-keep.mjs::an_empty_download_is_named
document-media-mismatchchecking document {document} downloaded as {file}its bytes are not the {media_type} the declaration states, so the program that reads it would read something else{file} ({bytes} bytes): {found}open this run's recording to see which file the site handed over; if the site now gives the report in another format, change the document's media type in the declaration and release it; nothing was keptunknown, exit 1, HTTP 500tests/trajectories/document-keep.mjs::a_download_of_another_media_type_is_named
document-keep-failedkeeping document {document} at {path}the documents folder cannot be written by the user the run runs as{answer}make {path} writable by that user, or set WELES_DOCUMENTS_DIR to a folder it can write, then run the document againconfig, exit 1, HTTP 503tests/trajectories/document-keep.mjs::a_document_that_cannot_be_kept_is_named
document-record-unreadablecomparing document {document} with the copies kept in {path}a record beside an earlier copy cannot be read as the keeper writes it, so whether this download is new cannot be told{record}: {answer}restore {record} from its copy, or remove it together with the document it describes, then run the document againconfig, exit 1, HTTP 503tests/trajectories/document-keep.mjs::an_unreadable_earlier_record_is_named
document-nothing-keptthe run of document {document} through {trajectory}the reviewed trajectory ended without handing a download to the keeper, so no document was fetched{trajectory} finished; no keepDocument or keepDownload call in this runopen this run's recording to see where the trajectory stopped; the trajectory must end by handing its download to keepDownloadunknown, exit 1, HTTP 500tests/trajectories/document-keep.mjs::a_trajectory_that_keeps_nothing_is_named
document-keep-count-invalidreading how many copies of document {document} weles documents prune keeps--keep is not a whole number of at least 1--keep {given}give --keep as the number of newest copies to keep, 1 or more; prune never removes every copyrefused, exit 2, HTTP 403tests/cli/documents.mjs::a_prune_keeping_no_whole_number_is_refused
document-prune-failedremoving an older copy of document {document}the copy or its record cannot be removed by the user weles runs as{path}: {answer}make the directory of {path} writable by that user and prune again; the copies listed before it were removedconfig, exit 1, HTTP 503tests/cli/documents.mjs::a_copy_that_cannot_be_removed_is_named
google-login-incompletereading the Google login item {item}the item lacks {field}: it was stored without it, or it is not a login itemitem {item}: no non-empty {field}store the login with fields.username and fields.password (and fields.totp_secret for an authenticator); `stado credentials get {item}` shows the item as the store holds itconfig, exit 1, HTTP 503tests/trajectories/google/google-sign-in-failures.mjs::a_login_without_a_password_is_named
google-identity-mismatchchoosing the Google SSO identity for {requested}the scoped Google SSO login this run holds is another accountrequested {requested}; the scoped login is {scoped}run with the account the scoped login holds, or scope the login of the requested account to this runconfig, exit 1, HTTP 503tests/trajectories/google/google-sign-in-failures.mjs::a_requested_account_the_scoped_login_is_not_is_named
google-totp-uri-secretlessreading the authenticator seed of {item}it is an otpauth URI without a secret parameter, so no code can be generatedan otpauth URI with parameters {parameters}store the seed again as the base32 secret or the whole otpauth URI Google showed; `stado credentials get {item}` shows the item as the store holds itconfig, exit 1, HTTP 503tests/trajectories/google/google-sign-in-failures.mjs::an_otpauth_uri_without_a_secret_is_named
google-totp-uri-parameterreading the authenticator seed of {item}it is an otpauth URI stating {name} {value}, which no code is computed with: the algorithm is SHA1, SHA256 or SHA512 and digits and period are whole numbers above zero (the Key URI Format); `skarbiec totp judge` calls an address it would not store invalid before any code is asked foran otpauth URI with {name}={value}store the whole otpauth URI Google showed with `skarbiec totp set`, which refuses one its codes are not computed with; `stado credentials get {item}` shows the item as the store holds itconfig, exit 1, HTTP 503tests/trajectories/google/google-sign-in-failures.mjs::an_otpauth_uri_with_a_parameter_no_code_is_computed_with_is_named
google-totp-emptyreading the authenticator seed of {item}it is blank, or decodes to no whole byte, so no code can be computed from it; `skarbiec totp seed` calls the same text declared_empty or invalid{length} charactersstore the base32 secret Google showed when the authenticator was added; `stado credentials get {item}` shows the item as the store holds itconfig, exit 1, HTTP 503tests/trajectories/google/google-sign-in-failures.mjs::an_empty_authenticator_seed_is_named
google-totp-character-invalidreading the authenticator seed of {item}it is not padded RFC 4648 Base32 as Skarbiec stores a seed (the letters A-Z and digits 2-7, then at most six = filling the last block of eight characters): lowercase, spaces and dashes are not read, exactly as `skarbiec totp seed` calls such a text invalidcharacter {character} at position {position} of {length}store the seed again with `skarbiec totp set`, which reads it as Google showed it and keeps it in that form; `stado credentials get {item}` shows the item as the store holds itconfig, exit 1, HTTP 503tests/trajectories/google/google-sign-in-failures.mjs::an_authenticator_seed_with_a_foreign_character_is_named
google-browser-not-securesigning in to GoogleGoogle refused the sign-in on its rejection page: it does not trust this browser or its address{url}the run's recording and page diagnosis at that step show Google's page; sign in from the account's own persona and proxy, or have the operator approve the device in the account's security settingsauth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_sign_in_google_refuses_as_not_secure_is_named
google-password-challenge-unavailablereaching the password step of the Google sign-inGoogle offered no password challenge among the ways to sign in (a passkey, a phone prompt or a code only){page}the run's recording and page diagnosis at that step show Google's page; let the account sign in with a password again in its Google security settingsauth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::an_account_without_a_password_challenge_is_named
google-password-rejectedsubmitting the password to GoogleGoogle marked the password field invalid: the stored password is not the account's{page}store the account's current password as fields.password of its login item (`stado credentials get <item>` shows the item)auth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_wrong_password_is_named
google-password-refusedsubmitting the password to GoogleGoogle stated a refusal on the password step (its alert below says why){page}the run's recording and page diagnosis at that step show Google's page; resolve what Google's alert states, then start a new run of the same action, which starts the sign-in againauth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_refusal_google_states_on_the_password_step_is_quoted
google-authenticator-unavailableanswering the second factor Google asks forGoogle asks for a second factor and the authenticator method could not be chosen, and a push or SMS loop is not starteda stored authenticator seed: {seeded}; {url}the run's recording and page diagnosis at that step show Google's page; add an authenticator to the account and store its seed as fields.totp_secretauth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_second_factor_without_the_authenticator_is_named
google-ended-during-approvalwaiting on Google's device prompt of the enrolment the owner ordered for {item}Google left its challenge while the run waited, so the approval has nothing to complete; nothing about the account changedGoogle moved to {detail}the order this run spent is used up; if the enrolment is still wanted it is an enrolment of {item}, which only the vault's owner orders in Skarbiec Desktop (https://skarbiec.wisent.com/docs/login/enrol-order), and the owner approves Google's prompt on the phoneauth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_challenge_google_ends_during_approval_is_named
google-phone-prompt-not-shownchoosing Google's phone prompt for the enrolment the owner ordered for {item}Google showed another page instead of the device prompt{url}the run's recording and page diagnosis at that step show Google's page; the order this run spent is used up; if the enrolment is still wanted it is an enrolment of {item}, which only the vault's owner orders in Skarbiec Desktop (https://skarbiec.wisent.com/docs/login/enrol-order)auth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_phone_method_that_shows_no_prompt_is_named
google-push-not-approvedcompleting the device prompt of the enrolment the owner ordered for {item}Google did not complete the prompt: it was declined on the phone, or it expired before it was approved{detail}the order this run spent is used up; if the enrolment is still wanted it is an enrolment of {item}, which only the vault's owner orders in Skarbiec Desktop (https://skarbiec.wisent.com/docs/login/enrol-order), and the owner approves Google's prompt on the phoneauth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_prompt_the_phone_declines_is_named
google-seed-missinganswering the second factor Google asks {item} forthe login keeps no working authenticator seed where it keeps its second factor, and no other method is chosen, so nothing reaches the owner's phone; what Google asked for is recorded on that item, so the next sign-in of the account is refused before the browser{page}store the account's seed (the seed or otpauth address on stdin to `skarbiec totp set` on the item `skarbiec login factor list {item}` names), or an enrolment of {item}, which only the vault's owner orders in Skarbiec Desktop (https://skarbiec.wisent.com/docs/login/enrol-order)auth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_code_challenge_without_a_seed_is_named
google-password-without-seedstarting the Google sign-in of {item}the login is read through scoped fields or a service credential, which carry no record of what its account asks after the password, and Skarbiec does not judge its seed present, so Google could answer its address or password with a prompt on the owner's phone; nothing was typed into Google's pageskarbiec totp judge: its seed is {seed}store the account's seed (the seed or otpauth address on stdin to `skarbiec totp set {item}`), or an enrolment of {item}, which only the vault's owner orders in Skarbiec Desktop (https://skarbiec.wisent.com/docs/login/enrol-order)auth, exit 1, HTTP 401tests/trajectories/google/google-scoped-seed.mjs::a_scoped_login_without_a_working_seed_sends_no_password
google-code-rejectedsubmitting the authenticator codeGoogle rejected the code the stored seed produced: the seed is not the account's current authenticator, or this host's clock is off{page}check the host clock, then replace the seed with `skarbiec totp set` on the item `skarbiec login factor list <login>` names, or with an enrolment of the login, which only the vault's owner orders in Skarbiec Desktop (https://skarbiec.wisent.com/docs/login/enrol-order)auth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_code_google_rejects_is_named
google-state-unreadablereading which second factor Google asks forthe page could not be read as a Google challenge: it navigated mid-read, or it is not Google's sign-in{page}the run's recording and page diagnosis at that step show Google's page; start a new run of the same action, which starts the sign-in againauth, exit 1, HTTP 401tests/trajectories/google/google-sign-in-failures.mjs::a_challenge_page_that_cannot_be_read_is_named
google-post-login-repeateddeclining what Google offers after the sign-inthe offer was declined and Google showed it again, so declining it does not move on{url}the run's recording and page diagnosis at that step show Google's page; accept or settle the offer in the account's settings once, then start a new run of the same action, which starts the sign-in againrefused, exit 1, HTTP 403tests/trajectories/google/google-sign-in-failures.mjs::an_offer_that_returns_after_it_is_declined_is_named
google-post-login-undismissabledeclining what Google offers after the sign-inthe page shows no control that declines or skips the offer{url}the run's recording and page diagnosis at that step show Google's page; settle the offer in the account's settings once, then start a new run of the same action, which starts the sign-in againrefused, exit 1, HTTP 403tests/trajectories/google/google-sign-in-failures.mjs::an_offer_without_a_way_to_decline_is_named
apple-ads-action-unknownfinding Apple Ads action {action} in the catalogue {catalogue}the catalogue declares no such action, and it is neither ads_cli nor ads_api_request{action} is not among the {count} actions declared, e.g. {examples}state APPLE_ADS_ACTION as one of the actions the catalogue declares (the keys of `actions` in its parts), or ads_cli with APPLE_ADS_CLI_ARGSrefused, exit 2, HTTP 403tests/trajectories/apple-ads-failures.mjs::an_action_the_catalogue_does_not_declare_is_named
apple-ads-input-undeclaredbuilding the asc arguments of Apple Ads action {action}the catalogue gives the action an input its own `inputs` do not declare, so no flag or environment value is known for itaction {action} names input {input}; the inputs declared: {declared}declare input {input} under `inputs` in src/trajectories/apple/ads/run/actions/, or correct the action's inputs thereconfig, exit 1, HTTP 503tests/trajectories/apple-ads-failures.mjs::an_action_naming_an_undeclared_input_is_named
apple-ads-value-missingbuilding the asc arguments of Apple Ads action {action}the action needs {label}, and the run states none{source} is unset or emptystate {label} (the run parameter of that name; {source} in the environment)refused, exit 2, HTTP 403tests/trajectories/apple-ads-failures.mjs::an_action_without_its_required_value_is_refused
apple-ads-cli-args-missingbuilding the asc arguments of Apple Ads action ads_cliads_cli runs the asc arguments the run states, and it states noneAPPLE_ADS_CLI_ARGS is unset or emptystate apple_ads_cli_args (APPLE_ADS_CLI_ARGS) with the asc arguments to run, and confirm the runrefused, exit 2, HTTP 403tests/trajectories/apple-ads-failures.mjs::raw_arguments_without_their_text_are_refused
apple-ads-cli-args-escapesplitting APPLE_ADS_CLI_ARGS into asc argumentsthe text ends in a backslash inside quotes, which escapes nothingAPPLE_ADS_CLI_ARGS ({length} characters) ends in \ inside {quote} quotes: …{tail}end the quoted argument after the escaped character, or remove the trailing backslashrefused, exit 2, HTTP 403tests/trajectories/apple-ads-failures.mjs::raw_arguments_ending_in_an_escape_are_refused
apple-ads-cli-args-quotesplitting APPLE_ADS_CLI_ARGS into asc argumentsa quote opened in the text is never closed, so where the argument ends is unknownAPPLE_ADS_CLI_ARGS ({length} characters): {quote} opened at character {opened} is not closedclose the quote opened at character {opened}refused, exit 2, HTTP 403tests/trajectories/apple-ads-failures.mjs::raw_arguments_with_an_open_quote_are_refused
apple-ads-unconfirmedrunning Apple Ads action {action}the action would {change}, and the run did not confirm itnone of APPLE_ADS_CONFIRM, WRITE_CONFIRM, SUBMIT is 1; asc was not runstate apple_ads_confirm=true, write_confirm=true or submit=true in the run parameters to {change}refused, exit 2, HTTP 403tests/trajectories/apple-ads-failures.mjs::a_change_the_run_did_not_confirm_is_refused
apple-ads-asc-unstartablestarting {program} for Apple Ads action {action}the asc program cannot be run: it is not on PATH, the path ASC_BIN names does not exist, or it is not executable{program}: {answer}put the asc program on PATH, or name its binary with ASC_BIN; `command -v asc` shows which one PATH finds and `asc --version` that it runsconfig, exit 1, HTTP 503tests/trajectories/apple-ads-failures.mjs::an_asc_that_cannot_be_started_is_named
apple-ads-asc-signalledrunning {program} for Apple Ads action {action}asc was ended by a signal before it finished, so whether the action took effect is unknownended by {signal}; its last words: {said}read the action's state in Apple Ads before running a change again (an ads_*_view or list action), then run it againinfra_down, exit 69, HTTP 503, retryabletests/trajectories/apple-ads-failures.mjs::an_asc_ended_by_a_signal_is_named
avatar-locator-invalidreading the character record's avatar to upload itavatar_url (or the first image) is not a private object under stado://weles/avatars/: a provider URL or another product's path would let the run fetch from an address nobody admittedavatar: {locator}store the image as a private object under stado://weles/avatars/<name> and set the character record's avatar_url to that URIrefused, exit 1, HTTP 403tests/trajectories/avatars/avatar-failures.mjs::an_avatar_outside_the_private_avatars_is_refused
avatar-not-imagemaking the avatar {locator} upright and squarethe object holds no image the image library can decode (its format is not one it reads, or the bytes are cut short){bytes} bytes beginning {head} (hex); decoder: {answer}store a PNG, JPEG or WebP image at {locator} (or point avatar_url at one), then run the edit againrefused, exit 1, HTTP 403tests/trajectories/avatars/avatar-failures.mjs::an_avatar_that_is_no_image_is_named
avatar-file-unwritablekeeping the avatar {locator} as a file to uploadthe temporary directory {directory} refused the file ({code}): it is not writable by the worker user, or its disk is full{path}: {answer}give the worker's user write access to {directory} (or point TMPDIR at a writable directory) and free space on its diskconfig, exit 1, HTTP 503tests/trajectories/avatars/avatar-failures.mjs::an_avatar_the_temporary_directory_refuses_is_named
media-image-absentreading the image {provider} generated for {model} through `{route}`the answer carries no base64 image in data[0].b64_json, which the request asked for with response_format b64_jsondata holds {count} entries; the first holds: {members}run `stado capabilities inference` to see which alternative served weles; an alternative that answers with a URL instead needs response_format b64_json honoured, or another alternative chosen with `stado capabilities select inference --order ...`unknown, exit 1, HTTP 500tests/trajectories/media-failures.mjs::an_answer_without_an_image_is_named
media-image-unwrittenkeeping the generated image in {directory}the recordings directory refused the file ({errno}): it is not writable by the worker user, or its disk is full{path}: {answer}; the image of {bytes} bytes was generated and is not keptgive the worker's user write access to {directory} (WELES_RECORDINGS_ROOT names its root) and free space on its disk, then run the post againconfig, exit 1, HTTP 503tests/trajectories/media-failures.mjs::an_image_the_recordings_refuse_is_named
ncbr-section-pattern-invalidselecting the sections of the application SECTION_PATTERN namesSECTION_PATTERN is not a regular expression JavaScript can compileSECTION_PATTERN: {pattern}: {answer}state SECTION_PATTERN as a regular expression matching "<number> <title>" of the sections, such as ^2\.refused, exit 2, HTTP 403tests/trajectories/parp_ncbr/ncbr-failures.mjs::a_section_pattern_that_does_not_compile_is_refused
ncbr-section-pattern-emptyselecting the sections of the application SECTION_PATTERN namesSECTION_PATTERN matches none of the sections an LSI2 application form holdsSECTION_PATTERN: {pattern}; the sections: {sections}state a SECTION_PATTERN that matches "<number> <title>" of at least one of {sections}, or leave it unset for every sectionrefused, exit 2, HTTP 403tests/trajectories/parp_ncbr/ncbr-failures.mjs::a_section_pattern_matching_no_section_is_refused
ncbr-sections-unanalyzedreading the Pangram analysis of each extracted sectionthe Pangram action of these sections ended without a trusted reading: it was refused, signed out, or its verdict could not be readsections {sections}; their logs are in {directory}read the logs in {directory}, correct what they name, then run the audit again with SECTION_PATTERN limited to those sectionsrefused, exit 1, HTTP 403tests/trajectories/parp_ncbr/ncbr-failures.mjs::a_section_pangram_did_not_analyze_is_named
linkedin-proxy-unrequestedreading the proxy {requested} the LinkedIn registration asks fora LinkedIn registration runs only through a dedicated ISP proxy, and the request asks for nonerequested {requested} from {variable}; no browser was openedrequest a dedicated ISP pool by its words, LINKEDIN_REGISTER_PROXY="isp <provider> <country>" (src/proxy/sources/pool_request.ts reads them), then run againrefused, exit 2, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_registration_asking_for_no_proxy_is_refused
linkedin-proxy-url-formreading the proxy {requested} the LinkedIn registration asks forthe request is a proxy URL, which names no provider or proxy type, so it cannot be judged a dedicated ISP exitrequested {requested} from {variable}; no browser was openedrequest a dedicated ISP pool by its words, LINKEDIN_REGISTER_PROXY="isp <provider> <country>" (src/proxy/sources/pool_request.ts reads them), then run againrefused, exit 2, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_registration_asking_for_a_proxy_url_is_refused
linkedin-proxy-session-unproxied{step} of the LinkedIn registrationthe session started without a proxy server although the registration asked for {requested}: the resolver handed it a direct connectionproxyConfig.server: {server}; provider {provider}; stage {step}the run's proxy_preflight.json under its recordings names each provider the resolver tried; restore a provider with a dedicated ISP pool, then run againconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_session_without_a_proxy_is_refused
linkedin-proxy-server-unparsablechecking the proxy record the LinkedIn registration session resolved tothe record names a proxy server that is no URL, so its host and port cannot be checked against the retired poolsserver of {length} characters, {userPart}; provider {provider}; the value is not shown, it may carry the passwordwrite the provider record's server as <scheme>://<host>:<port>, then run againconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_proxy_record_whose_server_is_no_url_is_refused
linkedin-proxy-provider-unstatedchecking the proxy record the LinkedIn registration session resolved tothe record names no provider, so the exit cannot be told a dedicated ISP oneserver {scheme}://{host}:{port}; requested {requested}; provider: nonestate the provider in the proxy record the resolver hands out for {requested}, or request another poolconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_proxy_record_without_a_provider_is_refused
linkedin-proxy-type-unstatedchecking the proxy record the LinkedIn registration session resolved tothe {provider} record names no proxy_type, so the exit cannot be told a dedicated ISP oneserver {scheme}://{host}:{port}; proxy_type: nonestate proxy_type isp in the {provider} record of a dedicated ISP pool, or request another poolconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_proxy_record_without_a_type_is_refused
linkedin-proxy-type-otherchecking the proxy record the LinkedIn registration session resolved tothe {provider} record is a {type} exit, and a LinkedIn registration runs only through a dedicated ISP one ({expected})proxy_type {type}; server {scheme}://{host}:{port}request a dedicated ISP pool by its words, LINKEDIN_REGISTER_PROXY="isp <provider> <country>" (src/proxy/sources/pool_request.ts reads them), then run againconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_proxy_record_of_another_type_is_refused
linkedin-proxy-retiredchecking the proxy record the LinkedIn registration session resolved tothe exit {host}:{port} belongs to a pool retired for LinkedIn ({reason}), so new accounts are not made through itSkarbiec's retired_proxy_pools names it: {reason}; provider {provider}request a dedicated ISP pool that is not retired; the retired_proxy_pools setting lists the retired onesrefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_proxy_of_a_retired_pool_is_refused
linkedin-proxy-rotatingchecking the proxy record the LinkedIn registration session resolved tothe {provider} record carries a rotating-pool session, so its exit address can change during the registration, which a dedicated ISP exit never doessticky_session_id of {length} characters; proxy_type {type}; server {scheme}://{host}:{port}remove the sticky session from the {provider} dedicated ISP record, or request its ISP pool instead of the rotating oneconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_proxy_record_of_a_rotating_pool_is_refused
linkedin-exit-probe-unansweredchecking the exit address of the LinkedIn registration at stage {stage}the exit address service {service} did not answer through the proxy: the proxy or its tunnel failed, or the service is downthe browser context said: {problem}; proxy {scheme}://{host}:{port}run again; when it keeps failing, the run's proxy_preflight.json under its recordings shows whether the provider's tunnel answeredinfra_down, exit 69, HTTP 503, retryabletests/trajectories/linkedin-register-failures.mjs::an_exit_probe_that_is_not_answered_is_named
linkedin-exit-probe-refusedchecking the exit address of the LinkedIn registration at stage {stage}the exit address service {service} answered HTTP {status} instead of the address, so the exit could not be readHTTP {status} {statusText}; proxy {scheme}://{host}:{port}run again once {service} answers; HTTP 407 means the proxy refused its login, 429 that the service limits this exitinfra_down, exit 69, HTTP 503, retryabletests/trajectories/linkedin-register-failures.mjs::an_exit_probe_answered_with_an_error_is_named
linkedin-exit-unreadchecking the exit address of the LinkedIn registration at stage {stage}the exit address service {service} answered {found} where it answers one IP addressanswer of {length} characters: {shown}; proxy {scheme}://{host}:{port}run again; an answer that is a page rather than an address means a captive portal or the proxy itself answeredinfra_down, exit 69, HTTP 503, retryabletests/trajectories/linkedin-register-failures.mjs::an_exit_probe_answering_no_address_is_named
linkedin-exit-driftedchecking the exit address of the LinkedIn registration at stage {stage}the browser is now seen from {actual}, not {expected}, the address the registration was bound to: the exit changed under itbound {expected} ({bound}); now {actual}; proxy {scheme}://{host}:{port}, provider {provider}run the registration again on a dedicated ISP exit that keeps its address; an exit that drifts is a rotating onerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::an_exit_that_changed_is_named
linkedin-preflight-unreadreading the run's proxy preflight record {path} for the failure diagnosticsthe record exists and the system refused to read it ({errno}), so the diagnostics cannot say which exits the resolver triedthe system said: {problem}; the registration had already failed with {failure}give this user read access to {path} (`ls -l {path}`); the registration's own failure is named above it in the run logconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_preflight_record_that_cannot_be_read_is_named
linkedin-preflight-not-jsonreading the run's proxy preflight record {path} for the failure diagnosticsthe record is not JSON: the preflight was cut short while writing it, or something else wrote it{bytes} characters; the parser said: {problem}; the registration had already failed with {failure}move {path} aside and run the registration again; the preflight writes a new oneconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_preflight_record_that_is_not_json_is_named
linkedin-submit-disabledsubmitting the LinkedIn signup form ({label})the submit button is shown and disabled: LinkedIn did not take what was typed into the formthe page is at {pageUrl}; nothing was sentthe run's recordings under linkedin_register/{label}.json keep the request and answer; run a new registration when the form's fields are what LinkedIn asks forrefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_disabled_submit_is_named
linkedin-submit-answer-unreadsubmitting the LinkedIn signup form ({label})the POST was answered and its body could not be read: the connection or the proxy's tunnel broke while it arrivedPOST {requestUrl} answered HTTP {status}; the page is at {pageUrl}; reading the body said: {problem}run again; the run's recordings under linkedin_register/{label}.json keep the request and answerinfra_down, exit 69, HTTP 503, retryabletests/trajectories/linkedin-register-failures.mjs::a_submit_answer_that_cannot_be_read_is_named
linkedin-submit-rate-limitedsubmitting the LinkedIn signup form ({label})LinkedIn answered HTTP 429: it limits signups from this exit or personaPOST {requestUrl} answered HTTP {status}; the page is at {pageUrl}wait before the next registration from this exit, or use another dedicated ISP exit; the run's recordings under linkedin_register/{label}.json keep the request and answerrate_limit, exit 69, HTTP 429, retryabletests/trajectories/linkedin-register-failures.mjs::a_submit_answered_with_a_rate_limit_is_named
linkedin-submit-refusedsubmitting the LinkedIn signup form ({label})LinkedIn refused the POST with HTTP {status}, a client error: it did not accept what the form sentPOST {requestUrl} answered HTTP {status}; the page is at {pageUrl}the run's recordings under linkedin_register/{label}.json keep the request and answerrefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_submit_refused_by_linkedin_is_named
linkedin-submit-server-failedsubmitting the LinkedIn signup form ({label})LinkedIn answered the POST with HTTP {status}, an error on its sidePOST {requestUrl} answered HTTP {status}; the page is at {pageUrl}run again later; the run's recordings under linkedin_register/{label}.json keep the request and answerinfra_down, exit 69, HTTP 503, retryabletests/trajectories/linkedin-register-failures.mjs::a_submit_linkedin_fails_is_named
linkedin-create-account-not-jsonreading what LinkedIn answered createAccountthe answer is not JSON, where createAccount answers its submissionId or challengeUrl as JSON: LinkedIn changed the call, or a page stood in for itPOST {requestUrl} answered HTTP {status}; the page is at {pageUrl}; {bytes} characters; the parser said: {problem}the run's recordings under linkedin_register/{label}.json keep the request and answerrefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_create_account_answer_that_is_not_json_is_named
linkedin-submit-diagnostics-unkeptkeeping the diagnostics {label} of a failed LinkedIn signup submitthe submit failed ({submitCause}) and its diagnostics could not be written ({keptCause})the submit said: {submit}; writing said: {kept}{keptFix}; then read the submit by its cause {submitCause}infra_down, exit 69, HTTP 503, retryabletests/trajectories/linkedin-register-failures.mjs::submit_diagnostics_that_cannot_be_kept_are_named
linkedin-challenge-shownreading the LinkedIn page at stage {stage}LinkedIn shows a {signal} instead of the next step of the signup: it suspects the registration, and this trajectory never solves a challengepage {url}; {inputs} visible inputs; challenge frames: {frames}this exit and persona are spent for LinkedIn: run a new registration on another dedicated ISP exit; the run's recordings under linkedin_register hold the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_challenge_page_is_named
linkedin-captcha-shownsubmitting the email and password of the LinkedIn signupLinkedIn answered the submit with a visible CAPTCHA, which this trajectory never solvespage {url}; a visible CAPTCHA frame or widget after the submitthis exit and persona are spent for LinkedIn: run a new registration on another dedicated ISP exit; the run's recordings under linkedin_register hold the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_captcha_after_the_submit_is_named
linkedin-create-account-challengedcreating the LinkedIn accountLinkedIn answered createAccount with a challenge ({kind}) instead of the accountchallenge {kind}, titled {title}, at {challengeUrl}this exit and persona are spent for LinkedIn: run a new registration on another dedicated ISP exit; the run's recordings under linkedin_register hold the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_create_account_challenge_is_named
linkedin-create-account-challenge-unreadcreating the LinkedIn accountLinkedIn answered createAccount with a challenge, and its page could not be read to tell which: the page closed or did not loadchallenge at {challengeUrl}; the page said: {problem}this exit and persona are spent for LinkedIn: run a new registration on another dedicated ISP exit; the run's recordings under linkedin_register hold the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_create_account_challenge_that_cannot_be_read_is_named
linkedin-signup-not-acceptedconfirming the LinkedIn registration at stage {stage}the page stayed on the signup form after the submit: LinkedIn rejected the registration without saying so, as it does on a low reCAPTCHA scorepage {url}this exit and persona are spent for LinkedIn: run a new registration on another dedicated ISP exit; the run's recordings under linkedin_register hold the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_registration_left_on_the_signup_form_is_named
linkedin-verification-incompleteconfirming the LinkedIn registration at stage {stage}the page is still a verification step ({route}) after the run answered it: LinkedIn did not take the mailed codepage {url}read the mail the run answered in the account's Skrzynka mailbox, then run a new registrationrefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_verification_left_unfinished_is_named
linkedin-session-unauthenticatedconfirming the LinkedIn registration at stage {stage}the browser holds no li_at cookie, so LinkedIn did not sign the new account in although the page moved onpage {url}; {cookies} linkedin.com cookies, none of them li_atthis exit and persona are spent for LinkedIn: run a new registration on another dedicated ISP exit; the run's recordings under linkedin_register hold the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_registration_without_a_session_is_named
linkedin-form-state-repeatedreaching the LinkedIn signup formthe page came back to a state it already showed after {action}, so another nudge would loop: no email and password fields appearpage {url} ({pageKey}); {inputs} inputs, {buttons} buttonsrun again; when it repeats, the run's recordings under linkedin_register (entry_path_diagnostics.json, the screenshots) show the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_signup_form_that_never_appears_is_named
linkedin-form-no-transitionreaching the LinkedIn signup formthe page is on /signup without the email and password fields, and it shows no link that leads furtherpage {url} ({pageKey}) after {action}; {inputs} inputs, {buttons} buttonsrun again; when it repeats, the run's recordings under linkedin_register (entry_path_diagnostics.json, the screenshots) show the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_signup_page_without_its_form_is_named
linkedin-entry-no-signup-linkwalking from the entry page {entry} to the LinkedIn signup formthe entry page shows no visible link to {signupPath}, so the run never reached the signup formthe page stopped at {url}set LINKEDIN_REGISTER_ENTRY_URL to a page that links to {signupPath}, or leave it unset to open the signup page directly; the run's recordings under linkedin_register (entry_path_diagnostics.json, the screenshots) show the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::an_entry_page_without_a_signup_link_is_named
linkedin-entry-no-arrivalwalking from the entry page {entry} to the LinkedIn signup formthe signup link was clicked and the browser never arrived at the signup formthe page stopped at {url}; waiting said: {problem}run again; when it repeats, the run's recordings under linkedin_register (entry_path_diagnostics.json, the screenshots) show the pagerefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::an_entry_link_that_leads_nowhere_is_named
linkedin-account-unsavedsaving the new LinkedIn account {handle} after it signed inthe account exists on LinkedIn and its record could not be saved: {lower}saving refused with {lowerCause}: {said}; its fix: {lowerFix}{lowerFix}; the LinkedIn account {handle} exists without a vault record and its password was not kept, so recover it by LinkedIn's password reset to its mailbox once the vault takes writesinfra_down, exit 69, HTTP 503, retryabletests/trajectories/linkedin-register-failures.mjs::an_account_that_cannot_be_saved_is_named
linkedin-fingerprint-inconsistentchecking the early fingerprint of the LinkedIn registration browserthe browser shows {critical} critical and {warning} warning findings against the baseline, at or past the limit of {limit} warnings, so LinkedIn would see the inconsistencyfindings {findings}; baseline {baseline}; the report is {report}read the findings in {report}; raise WELES_EARLY_FP_WARNINGS only when they are known to be harmless, or set WELES_EARLY_FP=0 to register without the checkrefused, exit 1, HTTP 403tests/trajectories/linkedin-register-failures.mjs::an_inconsistent_fingerprint_is_named
linkedin-fingerprint-uncheckedchecking the early fingerprint of the LinkedIn registration browserthere is no baseline directory {directory} to compare the early fingerprint withWELES_BASELINE_DIR {stated}; the directory does not existset WELES_BASELINE_DIR to the directory of fingerprint baselines, or WELES_EARLY_FP=0 to register without the checkconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_fingerprint_check_without_baselines_is_named
linkedin-verdict-unkeptkeeping the verdict {signal} of the LinkedIn registrationthe verdict could not be kept ({keptCause}), so the worker reads no signal for this runkeeping said: {kept}; the run itself ended with {runCause}: {run}{keptFix}; then read the run itself by its cause {runCause}infra_down, exit 69, HTTP 503, retryabletests/trajectories/linkedin-register-failures.mjs::a_verdict_that_cannot_be_kept_is_named
linkedin-entry-blankreading the entry page LINKEDIN_REGISTER_ENTRY_URL namesLINKEDIN_REGISTER_ENTRY_URL is set and holds no addressLINKEDIN_REGISTER_ENTRY_URL of {length} characters, all blank; no browser was openedset LINKEDIN_REGISTER_ENTRY_URL to a linkedin.com page that links to the signup form, or leave it unset to open https://www.linkedin.com/signup directlyrefused, exit 2, HTTP 403tests/trajectories/linkedin-register-failures.mjs::a_blank_entry_page_is_refused
linkedin-entry-not-urlreading the entry page LINKEDIN_REGISTER_ENTRY_URL namesthe entry page is no absolute URL, so the browser cannot open itLINKEDIN_REGISTER_ENTRY_URL {entry}; no browser was openedset LINKEDIN_REGISTER_ENTRY_URL to a linkedin.com page that links to the signup form, or leave it unset to open https://www.linkedin.com/signup directlyrefused, exit 2, HTTP 403tests/trajectories/linkedin-register-failures.mjs::an_entry_page_that_is_no_url_is_refused
linkedin-entry-host-foreignreading the entry page LINKEDIN_REGISTER_ENTRY_URL namesthe entry page is on {host}, not linkedin.com, so the walk would not reach the LinkedIn signup formLINKEDIN_REGISTER_ENTRY_URL {entry}; no browser was openedset LINKEDIN_REGISTER_ENTRY_URL to a linkedin.com page that links to the signup form, or leave it unset to open https://www.linkedin.com/signup directlyrefused, exit 2, HTTP 403tests/trajectories/linkedin-register-failures.mjs::an_entry_page_of_another_site_is_refused
linkedin-entry-cold-joinreading the entry page LINKEDIN_REGISTER_ENTRY_URL namesthe entry page carries trk=cold_join_sign_in, the sign-in page's join link, which LinkedIn reads as a cold signupLINKEDIN_REGISTER_ENTRY_URL {entry}; no browser was openedset LINKEDIN_REGISTER_ENTRY_URL to a linkedin.com page that links to the signup form, or leave it unset to open https://www.linkedin.com/signup directlyrefused, exit 2, HTTP 403tests/trajectories/linkedin-register-failures.mjs::an_entry_page_of_the_cold_join_link_is_refused
linkedin-warm-manifest-unreadreading the warm profile manifest {path}the manifest exists and the system refused to read it ({errno}): it is not readable by this user, or it is a directorythe system said: {problem}; no browser was openedgive this user read access to {path} (`ls -l {path}`), or warm the profile again with trajectories/linkedin/recover/signup/warm_signup_profile.mjs, which writes the manifest, or point LINKEDIN_REGISTER_WARM_PROFILE_DIR at another warm profileconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_warm_manifest_that_cannot_be_read_is_refused
linkedin-warm-manifest-not-jsonreading the warm profile manifest {path}the manifest is not JSON: it was cut short while written, or something else wrote it{bytes} characters; the parser said: {problem}; no browser was openedwarm the profile again with trajectories/linkedin/recover/signup/warm_signup_profile.mjs, which writes the manifest, or point LINKEDIN_REGISTER_WARM_PROFILE_DIR at another warm profileconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_warm_manifest_that_is_not_json_is_refused
linkedin-warm-manifest-schema-otherreading the warm profile manifest {path}the manifest is not a {expected} manifest, so the proxy and persona the profile was warmed with cannot be replayedschema {schema}; members {members}; no browser was openedwarm the profile again with trajectories/linkedin/recover/signup/warm_signup_profile.mjs, which writes the manifest, or point LINKEDIN_REGISTER_WARM_PROFILE_DIR at another warm profileconfig, exit 1, HTTP 503tests/trajectories/linkedin-register-failures.mjs::a_warm_manifest_of_another_schema_is_refused

run#

23 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
apple-authorization-invalidreading the authorization id of an Apple runthe authorization id the capabilities are bound to is no UUID (RFC 9562), so no capability can be checked against itauthorization id {authorization}start the run with the authorization id `weles login --provider apple` answeredrefused, exit 2, HTTP 400tests/runs/apple-capabilities-failures.mjs::an_authorization_that_is_no_uuid_is_refused
apple-capabilities-not-jsonreading {what} of the Apple run {authorization}{what} is text that is not JSON{length} characters, not shown (it holds capabilities); the parser refused it with a {kind}, whose words quote the text and are not shownsend the capabilities exactly as `weles login`, `weles agreement` or `weles certificate` issued them for this runrefused, exit 2, HTTP 400tests/runs/apple-capabilities-failures.mjs::capabilities_that_are_not_json_are_refused
apple-capabilities-not-objectreading {what} of the Apple run {authorization}{what} is {type}, not a JSON object{what}: {type}send the capabilities exactly as `weles login`, `weles agreement` or `weles certificate` issued them for this runrefused, exit 2, HTTP 400tests/runs/apple-capabilities-failures.mjs::capabilities_that_are_no_object_are_refused
apple-capabilities-fields-otherreading {what} of the Apple run {authorization}{what} must carry exactly {expected}, and carries other fieldsfields: {found}; missing: {missing}; not taken: {extra}send the capabilities exactly as `weles login`, `weles agreement` or `weles certificate` issued them for this runrefused, exit 2, HTTP 400tests/runs/apple-capabilities-failures.mjs::capabilities_with_other_fields_are_refused
apple-two-factor-mode-otherreading {what} of the Apple run {authorization}the two-factor source of an Apple run is one authorization-bound capability (mode capability), and it names another modetwo_factor.mode: {mode}send the capabilities exactly as `weles login`, `weles agreement` or `weles certificate` issued them for this runrefused, exit 2, HTTP 400tests/runs/apple-capabilities-failures.mjs::a_two_factor_mode_other_than_capability_is_refused
action-missingreading the action of POST /runthe body names no action, so there is no trajectory to runaction: {value}send "action": "<trajectory action>", one of the actions this worker servesrefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::a_run_without_an_action_is_refused
creds-mode-unknownreading creds of POST /runcreds is {mode}; it must be one of {modes}creds: {mode}send creds as one of {modes}, or leave it out to redact the runrefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::a_run_with_an_unknown_creds_mode_is_refused
raw-creds-forbiddenanswering POST /run with raw outputthis deployment does not return a run verbatim: its output may hold a credential, and WELES_API_ALLOW_RAW_CREDS is not set to 1creds: rawsend creds redact to read the run without its secrets, or store to read the account items it savedrefused, exit 2, HTTP 403tests/runs/submitting/request-failures.mjs::a_raw_run_where_the_deployment_forbids_it_is_refused
login-unnamedreading the login of {action}the run names its Skarbiec login by exactly one of login_role or login_item, a nonempty string, and takes no other key: {reason}params: {keys}send "login_role": "<role>" (the item tagged stado:role:<role>) or "login_item": "<item id>", and nothing else the action does not takerefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::a_google_run_naming_both_a_role_and_an_item_is_refused
mailbox-unnamedreading the mailbox of google_app_password{reason}params: {keys}send "organization": "<Skrzynka organization>" and "expected_account": "<mailbox email>" beside the loginrefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::an_app_password_run_without_its_organization_is_refused
oauth-client-unnamedreading the OAuth client and callback of google_oauth_callback{reason}params: {keys}send exactly one of "client_role": "<role>" or "client_item": "<item id>" and "callback": "<https URL with a host>" beside the loginrefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::an_oauth_callback_run_without_its_client_is_refused
fresh-profile-without-accountreading fresh_profile of POST /runa fresh browser profile is attached to an account, and the request names none, so it would sign in as nobodyfresh_profile: true; account_id: {account}send "account_id" with "fresh_profile": true, or leave fresh_profile outrefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::a_fresh_profile_without_an_account_is_refused
run-id-invalidreading run_id of a detached POST /runrun_id is not a run id: letters, digits, ., _ and -, starting with a letter or digitrun_id: {value}send run_id as such a name, or leave it out for one the worker makesrefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::a_detached_run_named_with_a_path_is_refused
param-missingreading params.{param} of a {action} runparams.{param} is not set, or blank, and {action} needs it: {what}params.{param}: {found}send params.{param} as {expected}refused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::a_run_without_a_parameter_its_action_needs_is_refused
param-invalidreading params.{param} of a {action} runparams.{param} is not {expected}params.{param}: {found}send params.{param} as {expected}refused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::a_run_with_a_parameter_of_another_shape_is_refused
analytics-action-undeclaredreading the inputs of the analytics action {action}no analytics-service catalog this worker reads declares {action}, so its inputs are unknowndeclared analytics actions: {declared}run one of the declared analytics actions, or declare {action} in its analytics-service catalog firstrefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::an_analytics_action_no_catalog_declares_is_refused
enrolment-unorderedadmitting the authenticator enrolment of {login}an enrolment signs in as the login, adds a sign-in method to the account (Google's security alert) and, from a browser profile Google has not seen, raises a prompt on the owner's phone, so it runs only on the vault owner's order: an order the owner makes in Skarbiec Desktop after Touch ID, signed by the order key its Secure Enclave keeps, which the run spends once in Skarbiec before anything opens; this request names no order; nothing was startedparams.enrol_order: {found}only the vault's owner orders an enrolment, in Skarbiec Desktop after Touch ID (https://skarbiec.wisent.com/docs/login/enrol-order); no automaton or agent orders one, and nothing in a request stands in for the orderrefused, exit 2, HTTP 400tests/runs/submitting/request-failures.mjs::an_enrolment_no_order_names_is_refused
action-unknownrunning {action}this release holds no trajectory for that action: it is misspelled, or it belongs to another releaseaction: {action}name an action this release's src/worker/deploy/weles-action-allowlist.txt holds, or install the release that carries itnot_found, exit 1, HTTP 404tests/runs/answers/answer-failures.mjs::a_run_of_an_action_no_trajectory_answers_is_not_found
run-failedrunning {action} to save its accounts (run {run_id})the trajectory ended without success, so it saved no account; its exit status and the end of its error output say whyexit {exit}read the run with `weles runs show {run_id}` for the step that failed, correct it and run againrefused, exit 1, HTTP 502tests/runs/answers/answer-failures.mjs::a_store_run_that_fails_names_its_run
no-account-savedreading the accounts run {run_id} of {action} savedthe run ended in success and saved no account item to the vault: the trajectory registers nothing in store mode, or the vault refused its writerun {run_id} saved no accountrun {action} with creds redact for its outcome, and `weles runs show {run_id}` for what it wroterefused, exit 1, HTTP 422tests/runs/answers/answer-failures.mjs::a_store_run_that_saves_no_account_is_refused
builder-bootstrap-unsetstarting the trajectory builderWELES_BUILDER_BOOTSTRAP_URL is not set, and it is the neutral page the builder agent starts onWELES_BUILDER_BOOTSTRAP_URL: not setdeclare WELES_BUILDER_BOOTSTRAP_URL in the worker's environment (`stado service env com.wisent.weles`), then `stado service restart com.wisent.weles`config, exit 1, HTTP 500tests/runs/submitting/builder-failures.mjs::a_builder_without_its_bootstrap_page_is_named
builder-instructions-emptyreading the instructions of POST /weles-builderthe body states no goal: it is empty, or its instructions member is blankinstructions: emptysend the goal as the body, as text or as {"instructions": "<goal>"}refused, exit 2, HTTP 400tests/runs/submitting/builder-failures.mjs::a_builder_request_without_a_goal_is_refused
builder-trajectory-missingstarting the trajectory builderthis release holds no generic_browser_task trajectory, which the builder runs: the release was built without itaction: generic_browser_taskinstall a weles-worker release that carries generic_browser_task through Stado (`stado product install weles --surface service`)config, exit 1, HTTP 500tests/runs/submitting/builder-failures.mjs::a_release_without_the_builder_trajectory_is_named

identity#

17 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
sms-country-unsupportedrenting a {country} number for {service}Weles knows no calling code of {country}, so no number of it can be written in international formcountry {country}; supported: {supported}; no number was boughtask one of {supported}refused, exit 2, HTTP 403tests/identity/sms-failures.mjs::a_number_of_an_unsupported_country_is_refused
sms-providers-unconfiguredrenting a {country} number for {service}the vault holds the API key of no SMS provider Weles rents fromjuicySms/api_key absent; smsActivate/api_key absent; no provider was askedstore one key: juicySms/api_key or smsActivate/api_key, as the Weles service secret (`stado capabilities resolve secrets --consumer weles` names the vault)config, exit 1, HTTP 503tests/identity/sms-failures.mjs::a_number_without_any_provider_key_is_refused
sms-number-unavailablerenting a {country} number for {service}no configured provider held a {country} number for {service}{answers}run again later, or top up the provider whose answer names its balance (NO_BALANCE); each provider's answer is named aboveinfra_down, exit 69, HTTP 503, retryabletests/identity/sms-failures.mjs::a_number_no_provider_holds_is_named
sms-order-provider-unknownreading order {order}the order names provider {provider}, which this Weles does not rent from: it was rented by another releaseproviders here: {providers}release the order in {provider}'s dashboard and rent a new numberunknown, exit 1, HTTP 500tests/identity/sms-failures.mjs::an_order_of_an_unknown_provider_is_named
sms-provider-unreachableasking {provider} to {step} (order {order})no HTTP answer came back from {host} ({errno}): the provider is down, or this host cannot reach it{problem}; nothing of the order changed on this siderun again once {host} answers (`curl -sI https://{host}/` shows whether it does)infra_down, exit 69, HTTP 503, retryabletests/identity/sms-failures.mjs::an_sms_provider_that_does_not_answer_is_named
sms-provider-key-refusedasking {provider} to {step} (order {order}){host} refused the API key with HTTP {status}: the key was revoked, or the account is closedHTTP {status}; {bytes} bytes, beginning {head}store the provider's API key as the Weles service secret {secret} in the vault Stado names for Weles (`stado capabilities resolve secrets --consumer weles`), with a key the provider's dashboard shows as activeauth, exit 1, HTTP 401tests/identity/sms-failures.mjs::an_sms_key_the_provider_refuses_is_named
sms-provider-unavailableasking {provider} to {step} (order {order}){host} answered HTTP {status}: it is overloaded or failing on its sideHTTP {status}; {bytes} bytes, beginning {head}run again later; the provider's status page says when it answers againinfra_down, exit 69, HTTP 503, retryabletests/identity/sms-failures.mjs::an_sms_provider_failing_on_its_side_is_named
sms-provider-refusedasking {provider} to {step} (order {order}){host} refused the request with HTTP {status}: its API changed the request it takesHTTP {status}; {bytes} bytes, beginning {head}compare the request in src/utils/identity/sms-providers/{provider}.ts with the provider's API documentationunknown, exit 1, HTTP 500tests/identity/sms-failures.mjs::an_sms_request_the_provider_refuses_is_named
sms-key-absentasking {provider} to {step} (order {order})the vault holds no {secret}, so {provider} cannot be asked about an order rented with it{secret}: absent; the order {order} is left as the provider holds itstore the provider's API key as the Weles service secret {secret} in the vault Stado names for Weles (`stado capabilities resolve secrets --consumer weles`)config, exit 1, HTTP 503tests/identity/sms-failures.mjs::an_order_whose_provider_key_is_gone_is_named
sms-answer-not-jsonasking {provider} to {step} (order {order}){provider} answered a number as text that opens like JSON and is not JSON: its API changed the answer{bytes} bytes; the parser said: {problem}; no number was takencompare the answer read in src/utils/identity/sms-providers/{provider}.ts with the provider's API documentationunknown, exit 1, HTTP 500tests/identity/sms-failures.mjs::a_number_answer_that_is_not_json_is_named
sms-code-unreadableasking {provider} to {step} (order {order}){provider} said the SMS arrived and handed over no digits: the service texted no code, or the provider's answer changed{provider} answered {answer}read the order in the provider's dashboard; ask a new number and run againunknown, exit 1, HTTP 500tests/identity/sms-failures.mjs::a_code_without_digits_is_named
sms-order-endedasking {provider} to {step} (order {order}){provider} says order {order} will receive no SMS ({state}): it expired, was cancelled, or the service sent nothing{provider} answered {answer}rent a new number (the run asks again when started again); the order is not reusedrefused, exit 1, HTTP 403tests/identity/sms-failures.mjs::an_order_that_will_receive_no_sms_is_named
symbols-emptygenerating an account passwordthe trajectory's rule for the provider's form names an empty alphabet of special characters, so no password can carry onesymbols: ""name the special characters the provider form accepts in the trajectory (registrationPassword({ symbols }))config, exit 1, HTTP 503tests/identity/password.mjs::a_rule_with_no_symbols_is_refused
policy-unstatedreading the length of a generated account passwordthe Skarbiec vault policy states no min_generated_length, which is where that length is statedthe vault policy holds no min_generated_lengthstate it once with `skarbiec policy set min_generated_length <length>`config, exit 1, HTTP 503tests/identity/password.mjs::a_vault_policy_without_a_length_is_named
length-unstatedreading the length of a generated account passwordthe vault is {store}, which keeps no policy, so the length is WELES_GENERATED_PASSWORD_LENGTH, and it is not setWELES_GENERATED_PASSWORD_LENGTH: not setset WELES_GENERATED_PASSWORD_LENGTH to the length every generated account password takes, in the environment Weles runs withconfig, exit 1, HTTP 503tests/identity/password.mjs::a_store_without_policy_and_no_length_is_named
length-invalidreading the length of a generated account passwordWELES_GENERATED_PASSWORD_LENGTH is not a whole number above zeroWELES_GENERATED_PASSWORD_LENGTH: {value}set WELES_GENERATED_PASSWORD_LENGTH to a whole number of characters, such as 24config, exit 1, HTTP 503tests/identity/password.mjs::a_length_that_is_not_a_number_is_named
length-shortgenerating an account passwordthe stated length is shorter than the number of character classes a password carries one of each (capitals, small letters, digits, special characters){source} is {length}; a password carries {classes} classesstate a length of at least {classes} in {source}config, exit 1, HTTP 503tests/identity/password.mjs::a_length_shorter_than_the_classes_is_refused

captcha#

29 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
captcha-callback-unsetgiving {service} the address it pushes its answer to{name} is {state}, so no provider can push its answer to this run ({meaning}){name} {state}; no task was createdstart the run through the Weles worker, which states WELES_CAPTCHA_CALLBACK_URL and WELES_CAPTCHA_ANSWERS_DIR for every run (it needs WELES_CAPTCHA_CALLBACK_ORIGIN, its public HTTPS origin)config, exit 1, HTTP 503tests/captcha/providers/provider-failures.mjs::a_solve_without_its_callback_is_refused
captcha-callback-url-invalidgiving {service} the address it pushes its answer toWELES_CAPTCHA_CALLBACK_URL is no absolute URL, so no address can be made from itWELES_CAPTCHA_CALLBACK_URL of {length} characters, beginning {head}; no task was createdset WELES_CAPTCHA_CALLBACK_ORIGIN of the worker to its public HTTPS origin (the worker states the run's callback URL from it)config, exit 1, HTTP 503tests/captcha/providers/provider-failures.mjs::a_callback_that_is_no_url_is_refused
captcha-callback-unwatchedwaiting for the answer of {service} in {directory}the answers directory could not be {step} ({errno}), so the answer the worker writes cannot be seen{path}: {problem}give the worker's user read and write access to {directory} (WELES_CAPTCHA_ANSWERS_DIR), then run againinfra_down, exit 69, HTTP 503, retryabletests/captcha/providers/provider-failures.mjs::an_answers_directory_that_cannot_be_used_is_named
captcha-callback-answer-not-jsonreading the answer of {service} the worker wrote to {path}the file is not the JSON the worker writes ({contentType, body}): another release of the worker wrote it{bytes} bytes; the parser said: {problem}run the run on a worker of the same release as its trajectory (`weles worker version`)unknown, exit 1, HTTP 500tests/captcha/providers/provider-failures.mjs::a_callback_answer_that_is_not_json_is_named
captcha-provider-unreachableasking {service} ({call})no HTTP answer came back from {host} ({errno}): the service is down or this host cannot reach it{problem}run again once {host} answers; the chain asks the next service whose key Weles holds meanwhileinfra_down, exit 69, HTTP 503, retryabletests/captcha/providers/provider-failures.mjs::a_service_that_does_not_answer_is_named
captcha-answer-not-jsonreading what {service} answered ({call})the service answered HTTP {status} with a body that is not JSON: an error page of the service or of a proxy before it{bytes} bytes as {kind}, beginning {head}; the parser said: {problem}run again later; the service's status page says whether it is failinginfra_down, exit 69, HTTP 503, retryabletests/captcha/providers/provider-failures.mjs::a_service_answer_that_is_not_json_is_named
captcha-service-refusedasking {service} ({call}){service} refused {call}: {code} {why}{service} answered {answer}act on the service's error code ({code}): a key it refuses (ERROR_KEY_DOES_NOT_EXIST, ERROR_WRONG_USER_KEY) is replaced in the vault, a balance it lacks (ERROR_ZERO_BALANCE) is topped up in its dashboard, a domain it does not ping back to is registered thererefused, exit 1, HTTP 403tests/captcha/providers/provider-failures.mjs::a_task_the_service_refuses_is_named
captcha-task-unnamedcreating a {type} task at {service}the service took the request and answered no task or job id, so its answer cannot be waited foranswer members: {members}; HTTP {status}compare the request in src/captcha/providers/ with the service's API documentation; the chain asks the next service meanwhileunknown, exit 1, HTTP 500tests/captcha/providers/provider-failures.mjs::a_task_without_an_id_is_named
captcha-task-failed{service} solving task {task} ({type})the service took the task and then gave up on it ({code}): {description}pushed errorId {error_id}, errorCode {code}run again; a task that fails for the page (ERROR_CAPTCHA_UNSOLVABLE) is solved by another service of the chain, or by the page from another exitrefused, exit 1, HTTP 403tests/captcha/providers/provider-failures.mjs::a_task_the_service_gives_up_is_named
captcha-task-unready{service} solving task {task} ({type})the service pushed its answer with status {status}, not ready: it pushes only finished tasks, so its callback protocol changedpushed members: {members}compare the callback reading in src/captcha/providers/api.ts with the service's callback documentation; the run waits at the callback until it is cancelled (`weles runs cancel <run-id>`)unknown, exit 1, HTTP 500tests/captcha/providers/provider-failures.mjs::a_task_pushed_unready_is_named
captcha-solution-empty{service} solving task {task} ({type})the service says the task is solved and its solution lacks {missing}, so nothing can be handed to the pagesolution members: {members}; values are not shown (they unlock the page)run again; when the service keeps answering so, compare the solution read in src/captcha/providers/ with the service's documentationunknown, exit 1, HTTP 500tests/captcha/providers/provider-failures.mjs::a_solution_without_its_token_is_named
captcha-pingback-unmatched{service} solving task {task} ({type})the pingback carried {found}, not this task's id and its code{kind} with fields {fields}the pingback route answers each run its own address; the run waits at the callback until it is cancelled (`weles runs cancel <run-id>`)unknown, exit 1, HTTP 500tests/captcha/providers/provider-failures.mjs::a_pingback_of_another_task_is_named
captcha-unconfiguredsolving {resource}no captcha service solves {resource} with a key Weles holdsservices with a key: {services}; none solves {resource}store a key of a service that solves it (capsolver, anticaptcha, capmonster, twocaptcha, nopecha or nocaptcha) as the Weles service secret <service>/api_key in the vault Stado names for Weles (`stado capabilities resolve secrets --consumer weles`)config, exit 1, HTTP 503tests/captcha/providers/provider-failures.mjs::a_challenge_no_held_key_solves_is_refused
captcha-unsolvedsolving {resource}no captcha service solved {resource}: each service whose key Weles holds was asked and none answered a solution{causes}act on each service's cause above; the run's captcha_events.json records the attempt as all_failedinfra_down, exit 69, HTTP 503, retryabletests/captcha/providers/provider-failures.mjs::a_challenge_no_service_solves_names_each
captcha-cost-not-numberrecording the price of the {provider} {resource} solvethe cost table priced it at {price}, which is not a number of dollars, and a solve is never recorded as freeprice {price} ({type})correct the {provider} {resource} price in the captcha table of @wisent/cost-tracker, the package src/utils/runtime/cost.ts prices with, and release Weles with itconfig, exit 1, HTTP 503tests/captcha/providers/provider-failures.mjs::a_solve_priced_at_no_number_is_refused
captcha-proxy-url-invalidnaming the proxy of the {resource} taskthe proxy is no URL, so no host, port or scheme can be handed to a serviceproxy of {length} characters; the parser said: {problem}; no service was askedstate the run's proxy as scheme://host:port (with user and password together when it logs in); the services take it soconfig, exit 1, HTTP 503tests/captcha/proxy-failures.mjs::a_proxy_that_is_no_url_is_refused
captcha-proxy-port-absentnaming the proxy of the {resource} taskthe proxy {host} names no port, and the services take a proxy as address and port, never one assumed for its schemeproxy {scheme}://{host} without a port; no service was askedstate the run's proxy as scheme://host:port (with user and password together when it logs in); the services take it soconfig, exit 1, HTTP 503tests/captcha/proxy-failures.mjs::a_proxy_without_a_port_is_refused
captcha-proxy-unresolvednaming the proxy of the {resource} taskthe proxy host {host} did not resolve ({errno}), and the services take the proxy by IP address{problem}; no service was asked`dig {host}` shows what the resolver answers; state the proxy by an address that resolves, then run againinfra_down, exit 69, HTTP 503, retryabletests/captcha/proxy-failures.mjs::a_proxy_whose_host_does_not_resolve_is_refused
captcha-proxy-password-absentnaming the proxy of the {resource} taskthe proxy {host} names the user {user} and no password, and {service} takes the proxy login as user and password togetheruser {user}; password not given; no service was askedstate the run's proxy as scheme://host:port (with user and password together when it logs in); the services take it soconfig, exit 1, HTTP 503tests/captcha/proxy-failures.mjs::a_proxy_user_without_a_password_is_refused
captcha-page-unstatedsolving a reCAPTCHA v2 tokenneither options.url nor the page states the address the token is solved for, and the services solve for a page addressoptions.url {url}; page.url() answered {page}pass the address of the page that shows the challenge as options.urlunknown, exit 1, HTTP 500tests/captcha/recaptcha-failures.mjs::a_token_solve_without_a_page_address_is_refused
recaptcha-image-unloadedsolving the reCAPTCHA image grid on {page}a tile image of the challenge finished loading with no picture: Google refused it to this exit, or it was cut offimage {image} has no natural widthrun again; when the images keep failing from this exit, run from another proxy exit. the run's recordings (vision/captcha_challenge_page.png, extracted_grid_latest.png) show the challengeinfra_down, exit 69, HTTP 503, retryabletests/captcha/recaptcha-failures.mjs::a_tile_image_that_did_not_load_is_named
recaptcha-instruction-emptysolving the reCAPTCHA image grid on {page}the visible image challenge states no instruction, so nothing says which tiles to chooseinstruction text {instruction}; grid {grid}the run's recordings (vision/captcha_challenge_page.png, extracted_grid_latest.png) show the challengeunknown, exit 1, HTTP 500tests/captcha/recaptcha-failures.mjs::a_challenge_without_an_instruction_is_named
recaptcha-grid-unseensolving the reCAPTCHA image grid on {page}the challenge frame holds no grid element, so no image can be taken of it: reCAPTCHA changed its markupno element matches {selector} in the frame {frame}the run's recordings (vision/captcha_challenge_page.png, extracted_grid_latest.png) show the challenge; correct GRID_SELECTOR in src/captcha/grid/classify_grid.ts to the grid it showsunknown, exit 1, HTTP 500tests/captcha/recaptcha-failures.mjs::a_challenge_frame_without_its_grid_is_named
recaptcha-tiles-unnamedsolving the reCAPTCHA image grid on {page}the vision model answered no list of tile numbersthe model answered {length} characters, beginning {head}run again; `stado capabilities resolve inference --consumer weles` shows which model Weles asksunknown, exit 1, HTTP 500tests/captcha/recaptcha-failures.mjs::a_model_that_names_no_tiles_is_named
recaptcha-tiles-invalidsolving the reCAPTCHA image grid on {page}the vision model listed tiles that are not whole tile numbers of the gridlisted {listed}; the grid has tiles 0 to {last}run again; `stado capabilities resolve inference --consumer weles` shows which model Weles asksunknown, exit 1, HTTP 500tests/captcha/recaptcha-failures.mjs::a_model_that_names_impossible_tiles_is_named
recaptcha-tile-unclickedsolving the reCAPTCHA image grid on {page}tile {tile} of the {count} chosen could not be clicked: the grid was replaced or covered while it was being solvedtiles chosen {tiles}; clicked before it {clicked}; Playwright said: {problem}run again; the run's recordings (vision/captcha_challenge_page.png, extracted_grid_latest.png) show the challengeunknown, exit 1, HTTP 500tests/captcha/recaptcha-failures.mjs::a_tile_that_cannot_be_clicked_is_named
recaptcha-verify-disabledsolving the reCAPTCHA image grid on {page}reCAPTCHA kept its verify button disabled after the tiles were chosen: it wants more tiles, or new tiles loadedtiles clicked {tiles}; #recaptcha-verify-button visible and disabledrun again; the run's recordings (vision/captcha_challenge_page.png, extracted_grid_latest.png) show the challengerefused, exit 1, HTTP 403tests/captcha/recaptcha-failures.mjs::a_verify_button_left_disabled_is_named
recaptcha-outcome-unobservedsolving the reCAPTCHA image grid on {page}the challenge frame disappeared before a checked anchor was seen, so whether the grid passed is not knowntiles clicked {tiles}; no challenge frame and no checked anchor on {page}read the page state before submitting; the run's recordings (vision/captcha_challenge_page.png, extracted_grid_latest.png) show the challengeunknown, exit 1, HTTP 500tests/captcha/recaptcha-failures.mjs::a_challenge_that_vanishes_unchecked_is_named
recaptcha-rejectedsolving the reCAPTCHA image grid on {page}reCAPTCHA rejected the tiles chosen ({state}); the solve is not repeated, since a retried image flags the sessiontiles clicked {tiles}; reCAPTCHA said {said}start a new run, from another exit when it keeps being rejected; the run's recordings (vision/captcha_challenge_page.png, extracted_grid_latest.png) show the challengerefused, exit 1, HTTP 403tests/captcha/recaptcha-failures.mjs::a_grid_recaptcha_rejects_is_named

secrets#

100 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
managed-path-relativereading the managed password declarations WELES_MANAGED_PASSWORD_CONTRACTS_FILE names ({path})WELES_MANAGED_PASSWORD_CONTRACTS_FILE names a relative path, which would be read against whatever directory the worker started inWELES_MANAGED_PASSWORD_CONTRACTS_FILE: {path}; nothing was readset WELES_MANAGED_PASSWORD_CONTRACTS_FILE to the absolute path of the declarations fileconfig, exit 1, HTTP 503tests/secrets/skarbiec_vault/managed-failures.mjs::a_relative_declarations_path_is_refused
managed-file-unreadreading the managed password declarations WELES_MANAGED_PASSWORD_CONTRACTS_FILE names ({path})the file could not be {step} ({errno}): it is absent, or the worker user may not read it{problem}place the declarations at {path} readable by the worker user, or unset WELES_MANAGED_PASSWORD_CONTRACTS_FILEconfig, exit 1, HTTP 503tests/secrets/skarbiec_vault/managed-failures.mjs::a_declarations_file_that_is_absent_is_named
managed-file-unfitreading the managed password declarations WELES_MANAGED_PASSWORD_CONTRACTS_FILE names ({path})the declarations decide which credentials Weles writes, so only a regular owner-only file of the worker user is read, and this one is not: {why}{state}; worker uid {uid}make {path} a regular file owned by the worker user with mode 0600 (`chmod 600 {path}`)config, exit 1, HTTP 503tests/secrets/skarbiec_vault/managed-failures.mjs::a_declarations_file_others_may_read_is_refused
managed-file-not-jsonreading the managed password declarations WELES_MANAGED_PASSWORD_CONTRACTS_FILE names ({path})the file is not JSON{bytes} bytes; the parser said: {problem}write {path} as {"schema": "weles.managed-passwords.v1", "accounts": [{"item": "<item or role:<role>>", "provider": "microsoft|microsoft_entra|parp"}]}config, exit 1, HTTP 503tests/secrets/skarbiec_vault/managed-failures.mjs::a_declarations_file_that_is_not_json_is_refused
managed-file-shapereading the managed password declarations WELES_MANAGED_PASSWORD_CONTRACTS_FILE names ({path})the file is JSON without schema weles.managed-passwords.v1 and an accounts list, or with members of no such filemembers: {members}; schema {schema}; accounts {accounts}write {path} as {"schema": "weles.managed-passwords.v1", "accounts": [{"item": "<item or role:<role>>", "provider": "microsoft|microsoft_entra|parp"}]}config, exit 1, HTTP 503tests/secrets/skarbiec_vault/managed-failures.mjs::a_declarations_file_of_another_shape_is_refused
managed-account-invalidreading the managed password declarations WELES_MANAGED_PASSWORD_CONTRACTS_FILE names ({path})account {index} is no exact item or role:<role> (1-128 ASCII letters, digits, dots, underscores or hyphens, starting with a letter or digit) with provider microsoft, microsoft_entra or parpaccount {index}: {found}correct account {index} of {path}config, exit 1, HTTP 503tests/secrets/skarbiec_vault/managed-failures.mjs::a_declared_account_of_another_shape_is_refused
managed-item-repeatedreading the managed password declarations WELES_MANAGED_PASSWORD_CONTRACTS_FILE names ({path})the item {item} is declared twice, so which provider writes it is not one answeraccounts {first} and {index} both name {item}keep one declaration of {item} in {path}config, exit 1, HTTP 503tests/secrets/skarbiec_vault/managed-failures.mjs::an_item_declared_twice_is_refused
managed-item-takenresolving the acquisition contract of {secret}the declarations name {item}, which this release's own {owner} already holds, and a declaration cannot replace a contract the release carries{path} declares {item} as a managed password; nothing was written or readremove {item} from {path}, or declare the password under an item of its ownconfig, exit 1, HTTP 503tests/secrets/skarbiec_vault/managed-failures.mjs::a_declared_item_the_release_holds_is_refused
capability-literal-environmentchecking a literal the model gave for a fieldthe literal names an environment variable ({reference}), and model input never reads the environment{length} characters, naming {reference}pass the value itself, or fill the field with fill_credential and a capability referencerefused, exit 2, HTTP 403tests/secrets/scoping/capability-failures.mjs::a_literal_naming_an_environment_variable_is_refused
capability-literal-redeemedchecking a literal the model gave for a field[credential_literal] the literal equals secret material a capability redeemed in this process, so typing it would put the secret where no capability bounds it{length} characters; its SHA-256 is among the {redeemed} digests this process redeemed; the value is not shownfill credential fields with fill_credential and a capability reference, never with a literalrefused, exit 2, HTTP 403tests/secrets/scoping/capability-failures.mjs::a_literal_equal_to_redeemed_material_is_refused
capability-reference-invalidchecking the capability handed for {purpose} on {resource}invalid capability reference: {problem}members {members}; target {target}pass the capability object exactly as it was handed to the run: capability_id (64 hex), purpose, resource, target "weles", and an optional authorization_id (a UUID)refused, exit 2, HTTP 403tests/secrets/scoping/capability-failures.mjs::a_reference_of_another_shape_is_refused
capability-operation-mismatchchecking the capability handed for {purpose} on {resource}the capability was minted for {given}, and this operation redeems one for {expected}given {given}; expected {expected}pass the capability the run was handed for this operation; a capability is bound to one purpose, resource and authorizationrefused, exit 2, HTTP 403tests/secrets/scoping/capability-failures.mjs::a_reference_for_another_operation_is_refused
capability-provider-resource-invalidchecking the {purpose} capability handed to a provider callits resource {resource} names no provider: a provider capability's resource is provider:<name>resource {resource}pass the provider capability the run was handed, whose resource is provider:<name>refused, exit 2, HTTP 403tests/secrets/scoping/capability-failures.mjs::a_provider_capability_naming_no_provider_is_refused
capability-setting-invalidreading the capability broker setting {name}{name} is {state}, and the broker cannot be asked without it{name}: {state}set {name} in the worker's service unit as Stado declares it for this workload, with no surrounding spacesconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::a_broker_setting_that_is_unset_is_refused
capability-path-relativereading the capability broker setting {name}{name} is a relative path, which would be read from whatever directory the run started in{name} of {length} characters, not starting with /set {name} in the worker's service unit as Stado declares it for this workload, with no surrounding spacesconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::a_relative_broker_path_is_refused
capability-id-invalidasking the capability broker to {operation} a capabilitythe {what} is not {shape}, so the broker would refuse it unread{what} of {length} characterspass the capability exactly as it was handed to the runrefused, exit 1, HTTP 403tests/secrets/scoping/capability-failures.mjs::a_capability_id_of_another_shape_is_refused
capability-workload-id-invalidsigning the workload proof to {operation} capability {capability}SKARBIEC_WORKLOAD_ID is {problem}, which the proof cannot carrySKARBIEC_WORKLOAD_ID of {length} characters (at most 128, no NUL, CR or LF)set SKARBIEC_WORKLOAD_ID in the worker's service unit as Stado declares it for this workload, with no surrounding spacesconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::a_workload_id_the_proof_cannot_carry_is_refused
capability-key-unreadablereading the workload signing key {path}the key cannot be read ({errno}): it does not exist, or the worker's user may not read it{path}: {problem}point SKARBIEC_WORKLOAD_SIGNING_KEY_FILE at this workload's Ed25519 key, an absolute path to a regular file owned by the worker's user with mode 600, as its service unit declares itconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::a_signing_key_that_does_not_exist_is_named
capability-key-unsafereading the workload signing key {path}the key is {problem}, and a key another user can read proves nothing of this workload{path}: {kind}, mode {mode}, owner uid {owner}; this process runs as uid {uid}point SKARBIEC_WORKLOAD_SIGNING_KEY_FILE at this workload's Ed25519 key, an absolute path to a regular file owned by the worker's user with mode 600, as its service unit declares itconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::a_signing_key_others_may_read_is_refused
capability-key-unusablesigning the workload proof with {path}the file holds no private key this process can sign with ({problem}), or one that is not Ed25519 (its proof is {proof} characters, an Ed25519 one 86){path}: {bytes} bytes; the key is not shownpoint SKARBIEC_WORKLOAD_SIGNING_KEY_FILE at this workload's Ed25519 key, an absolute path to a regular file owned by the worker's user with mode 600, as its service unit declares itconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::a_signing_key_that_is_no_key_is_refused
capability-broker-unreachableasking the capability broker at {socket} to {operation} capability {capability}the broker's socket did not take the request ({errno}): no broker listens at that path, or the worker's user may not open it{socket}: {problem}`stado service status skarbiec` shows whether the broker runs; SKARBIEC_CAP_SOCKET must be the socket it listens oninfra_down, exit 69, HTTP 503, retryabletests/secrets/scoping/capability-failures.mjs::a_broker_socket_nothing_listens_on_is_named
capability-answer-truncatedreading the broker's answer to {operation} capability {capability} at {socket}the broker closed the socket before it ended its answer, so what it sent is not read{bytes} bytes received before the socket closedask again; `stado service logs skarbiec` shows why the broker closed itinfra_down, exit 69, HTTP 503, retryabletests/secrets/scoping/capability-failures.mjs::a_broker_answer_cut_off_is_named
capability-control-line-invalidreading the broker's answer to {operation} capability {capability} at {socket}the answer does not begin with one control line ended by LF{bytes} bytes; first LF at {newline}compare the broker's Skarbiec release with the protocol this workload speaks (skarbiec.redeem.v1: one JSON control line, then the secret_len bytes it names); `stado service logs skarbiec` shows its sideconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::capability_control_line_invalid_is_named
capability-control-not-jsonreading the broker's answer to {operation} capability {capability} at {socket}the control line is not JSONcontrol line of {length} bytes; the parser said: {problem}compare the broker's Skarbiec release with the protocol this workload speaks (skarbiec.redeem.v1: one JSON control line, then the secret_len bytes it names); `stado service logs skarbiec` shows its sideconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::capability_control_not_json_is_named
capability-control-not-objectreading the broker's answer to {operation} capability {capability} at {socket}the control line is JSON but not an objectthe control line is {kind}compare the broker's Skarbiec release with the protocol this workload speaks (skarbiec.redeem.v1: one JSON control line, then the secret_len bytes it names); `stado service logs skarbiec` shows its sideconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::capability_control_not_object_is_named
capability-version-otherreading the broker's answer to {operation} capability {capability} at {socket}the control line speaks {version}, not skarbiec.redeem.v1version {version}compare the broker's Skarbiec release with the protocol this workload speaks (skarbiec.redeem.v1: one JSON control line, then the secret_len bytes it names); `stado service logs skarbiec` shows its sideconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::capability_version_other_is_named
capability-status-framing-invalidreading the broker's answer to {operation} capability {capability} at {socket}a {status} answer carries more than version and status, or a bodymembers {members}; body of {bytes} bytescompare the broker's Skarbiec release with the protocol this workload speaks (skarbiec.redeem.v1: one JSON control line, then the secret_len bytes it names); `stado service logs skarbiec` shows its sideconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::capability_status_framing_invalid_is_named
capability-status-unknownreading the broker's answer to {operation} capability {capability} at {socket}the control line's status is {status}, none of ok, denied or pendingstatus {status}compare the broker's Skarbiec release with the protocol this workload speaks (skarbiec.redeem.v1: one JSON control line, then the secret_len bytes it names); `stado service logs skarbiec` shows its sideconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::capability_status_unknown_is_named
capability-success-framing-invalidreading the broker's answer to {operation} capability {capability} at {socket}an ok answer carries other members, or a secret_len that is not the length of its bodymembers {members}; secret_len {declared}; body of {bytes} bytescompare the broker's Skarbiec release with the protocol this workload speaks (skarbiec.redeem.v1: one JSON control line, then the secret_len bytes it names); `stado service logs skarbiec` shows its sideconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::capability_success_framing_invalid_is_named
capability-cancel-materialreading the broker's answer to {operation} capability {capability} at {socket}the broker answered a cancellation with secret material, which a cancellation never returnsbody of {bytes} bytes, wiped unreadcompare the broker's Skarbiec release with the protocol this workload speaks (skarbiec.redeem.v1: one JSON control line, then the secret_len bytes it names); `stado service logs skarbiec` shows its sideconfig, exit 1, HTTP 503tests/secrets/scoping/capability-failures.mjs::capability_cancel_material_is_named
capability-deniedasking the capability broker at {socket} to {operation} capability {capability}the broker refused to {operation} capability {capability}: capability denied; no retry is permitted (it was spent, expired, cancelled, or minted for another workload)status denied; {refusal}read why with the command the observed state names, then ask whoever handed the run the capability for a new one; a denied capability is never redeemedrefused, exit 1, HTTP 403tests/secrets/scoping/capability-failures.mjs::a_capability_the_broker_denies_is_named
capability-pendingasking the capability broker at {socket} to {operation} capability {capability}capability material is pending: the broker holds the capability and its material is not ready yet (an approval or code still awaited)status pendingask again once the material is ready; the run waiting on it retriestimeout, exit 69, HTTP 504, retryabletests/secrets/scoping/capability-failures.mjs::a_capability_still_pending_is_named
alternative-unansweredfinding the secrets alternative Stado names for Welesno alternative of the secrets family answers Weles: the Skarbiec service of this host is stopped or absent from the service directory, and no other alternative is configured{answer}run `stado capabilities resolve secrets --consumer weles`, which names each alternative and why it did not answer; start the one it names with `stado service ensure skarbiec --host <this host> --reason <why>`infra_down, exit 69, HTTP 503, retryabletests/secrets/alternative-failures.mjs::a_host_where_no_secrets_alternative_answers_names_each
alternative-invalidreading the secrets alternative Stado names for WelesStado answered an alternative with no provider, or with a route Weles may not use: for Skarbiec not an http(s) origin, carrying credentials, a query, a fragment or a path, or plain HTTP to an address that is not this machine's loopback; for the owner file not a file:// URL of an absolute path; an older Stado, or something writing to its standard outputStado answered {answer}upgrade Stado to the version this Weles release names as minimum_stado_version, then run `stado capabilities resolve secrets --consumer weles` againconfig, exit 1, HTTP 503tests/secrets/alternative-failures.mjs::an_alternative_without_a_route_is_named
provider-unsupported{need} through the {provider} alternative at {route}it needs Skarbiec's operator API, and Stado handed out another provider first: the owner-only credential file answers item reads and writes only (no scoped grants, acquisitions or worker vault endpoint), and a provider this Weles does not know answers nothing it speaksStado named {provider} ({kind}) at {route}; the order is {order}make Skarbiec answer Weles on this host (`stado capabilities resolve secrets --consumer weles` names why it did not), so it is handed out firstconfig, exit 1, HTTP 503tests/secrets/alternative-failures.mjs::an_alternative_that_is_not_skarbiec_is_refused
vault-unreachableskarbiec {command} through {route}nothing answered at the route Stado proved, even after Stado proved the alternative again: Skarbiec stopped between the proof and the request, or Stado then handed out another store, which holds other items, so the request is not sent there{answer}start Skarbiec with `stado service ensure skarbiec --host <this host> --reason <why>`, then run againinfra_down, exit 69, HTTP 503, retryabletests/secrets/alternative-failures.mjs::a_route_nothing_answers_on_is_named
vault-refusedskarbiec {command} through {route}Skarbiec answered and refused; its own words name the vault, the item or the key it could not useHTTP {status}: {answer}run `stado credentials doctor` for whether a key on this machine opens the vault, correct what Skarbiec names, then run againrefused, exit 1, HTTP 403tests/secrets/alternative-failures.mjs::a_skarbiec_that_refuses_is_quoted
vault-answer-invalidreading what skarbiec {command} answered through {route}it answered success without the JSON {expected}: what answers at the route is not Skarbiec, or an older Skarbiec{answer}run `stado capabilities resolve secrets --consumer weles` for what answers there, and install Skarbiec through Stado (`stado product install skarbiec --surface service`)config, exit 1, HTTP 503tests/secrets/alternative-failures.mjs::a_skarbiec_answer_that_is_not_json_is_named
bridge-missingstarting the request thread {path}the file a vault request runs in is absent from this install: it was built or copied without it{path} does not existinstall the Weles release again through Stado (`stado product install weles --surface cli`)config, exit 1, HTTP 503tests/secrets/alternative-failures.mjs::an_install_without_its_request_thread_is_named
owner-file-read-refused`stado {command}` reading the owner-file credential store {route}Stado refused to read the store in its own words below: the file was removed since Stado named it, this user may not read it, others may read or write it (Stado refuses a store that is not owner-only), or it is not the JSON object of items Stado keepsexit {status}: {answer}correct what Stado names (`stado credentials ls` reads the store, `stado config get credentials.store` names its file), restore the file from its backup or point credentials.store at the right one (`stado config set credentials.store file://<path>`)config, exit 1, HTTP 503tests/secrets/owner-file.mjs::a_store_stado_refuses_to_read_quotes_stado
owner-file-item-absent{command} item {id} in the owner-file credential store {route}the store holds no item of that id: it was never written there, it was removed, or it lives in another store (a Skarbiec vault the host used before)Stado said: {answer}`stado credentials ls` lists the items the store holds; write the item with `stado credentials put {id}` or name one it holdsnot_found, exit 1, HTTP 404tests/secrets/owner-file.mjs::an_item_the_store_lacks_is_named
owner-file-item-not-documentreading item {id} of the owner-file credential store {route} as a JSON documentthe item holds text that is not JSON: it was written with `stado credentials put` by another program, or by hand, as a bare value, while Weles keeps every record as one JSON document{answer}write the item again as the JSON document Weles keeps (`stado credentials get {id}` shows what it holds now), or remove it with `stado credentials rm {id}` when it is not a Weles recordconfig, exit 1, HTTP 503tests/secrets/owner-file.mjs::an_item_holding_bare_text_is_named
owner-file-tags-malformedreading the tags of item {id} in the owner-file credential store {route}the store has no tags, so Weles keeps an item's tags in its document's `tags` member as a list of text; this item's member is something else, written by hand or by another programtags: {tags}write the item again with `tags` a list of text, or without the member (`stado credentials get {id}` shows it, `stado credentials put {id}` replaces it)config, exit 1, HTTP 503tests/secrets/owner-file.mjs::an_item_whose_tags_are_not_text_is_named
owner-file-item-changedreplacing item {id} in the owner-file credential store {route} only if it is unchangedthe item no longer holds the document the caller read: another writer changed it in between, so writing would lose that changeitem {id} differs from what was readread item {id} again (`stado credentials get {id}`) and run the operation again against what it holds nowrefused, exit 1, HTTP 403tests/secrets/owner-file.mjs::an_item_changed_since_it_was_read_is_not_replaced
owner-file-write-refused`stado {command}` on the owner-file credential store {route}Stado refused the write in its own words below: the store's directory does not let this user replace the file, the item id is one Stado reserves, or STADO_CREDENTIALS_STORE names another store than credentials.store (a migration not finished)exit {status}: {answer}correct what Stado names (`stado credentials ls` reads the store, `stado credentials migrate` finishes a migration), then run againrefused, exit 1, HTTP 403tests/secrets/owner-file.mjs::a_write_stado_refuses_quotes_stado
identity-undeclaredfinding the consumer and bearer Weles presents to the Skarbiec at {route}Skarbiec serves its routes only to a caller that proves who it is, and Stado declares no grant of the Skarbiec consumer weles with one bearer file by its absolute path for Weles on the skarbiec service: none is declared, several name different files, or the file is not named by an absolute path`stado capabilities resolve secrets --consumer weles` declares: {found}declare where Weles's bearer is kept with `stado service directory consumer add skarbiec weles --grant-consumer weles --grant <one capability of it, action:item#field> --token-file <absolute owner-only file>`; `stado capabilities resolve secrets --consumer weles` then lists it under grants; the grant itself is issued on the vault owner (`skarbiec grant issue weles --capabilities <...> --token-file <that file> --until-revoked`)config, exit 1, HTTP 503tests/secrets/skarbiec_vault/skarbiec-identity.mjs::a_skarbiec_with_no_grant_declared_for_weles_is_named
bearer-unsafereading Weles's Skarbiec bearer from {file}the file Stado declares for the bearer cannot be trusted or read: it is absent (the grant's file was declared and no bearer written into it), a link, not a regular file, another account's, or open to its group or others{file} {reason}write a new random bearer alone on one line into {file} with mode 0600, then register it on the vault owner: `skarbiec grant issue weles --capabilities <its capabilities> --replace-capabilities --token-file {file} --until-revoked`; a file others could read held a bearer another account may have, which the new one replaces on the vault ownerconfig, exit 1, HTTP 503tests/secrets/skarbiec_vault/skarbiec-identity.mjs::a_bearer_file_open_to_others_is_refused_and_nothing_is_sent
bearer-malformedreading Weles's Skarbiec bearer from {file}the file holds {held}, and a bearer is one word on one line, read as Skarbiec reads a --token-file: trailing line breaks off and nothing else trimmed{file} holds {held}write a new random bearer alone on one line into {file} with mode 0600, then register it on the vault owner: `skarbiec grant issue weles --capabilities <its capabilities> --replace-capabilities --token-file {file} --until-revoked`config, exit 1, HTTP 503tests/secrets/skarbiec_vault/skarbiec-identity.mjs::a_bearer_file_holding_whitespace_inside_is_refused
scoped-service-undeclaredusing the scoped credentials of service {service}the service catalog src/secrets/scoped-service/catalog/services.json declares no service of that name: the trajectory names a service this release does not carrythe catalog declares {count} servicesinstall the Weles release whose catalog declares {service} (`stado product install weles --surface cli`), or declare it in src/secrets/scoped-service/catalog/services.jsonconfig, exit 1, HTTP 503tests/secrets/scoping/scoped.mjs::a_service_the_catalog_lacks_is_named
scoped-service-not-loginusing service {service} as a loginthe catalog declares the service without both a username and a password field, so it holds no login to sign in withits fields are {fields}declare username and password fields for {service} in src/secrets/scoped-service/catalog/services.json, or read its fields one by oneconfig, exit 1, HTTP 503tests/secrets/scoping/scoped.mjs::a_service_without_a_login_is_refused_as_one
scoped-field-undeclaredreading field {field} of service {service}the catalog does not declare that field for the service, so no grant or item carries itits fields are {fields}read one of the declared fields, or declare {field} for {service} in src/secrets/scoped-service/catalog/services.jsonconfig, exit 1, HTTP 503tests/secrets/scoping/scoped.mjs::a_field_the_service_lacks_is_named
scoped-field-absentreading field {field} of service {service} from item {item} of the {provider} store {route}the store holds no non-empty value of that field: the credential was never written there, or it was written without ititem {item} holds no {field}write the credential with the trajectory that acquires it, or with `stado credentials put --role {item} --type <kind>`, then run againnot_found, exit 1, HTTP 404tests/secrets/scoping/scoped.mjs::a_field_the_store_lacks_is_named
scoped-identity-absentreading field {field} of service {service} from Skarbiecthe vault is a Skarbiec, which hands a field out only to a workload identity, and this process carries noneSKARBIEC_WORKLOAD_ID or SKARBIEC_WORKLOAD_SIGNING_KEY_FILE is not setrun the trajectory as the Weles worker does, with SKARBIEC_WORKLOAD_ID and SKARBIEC_WORKLOAD_SIGNING_KEY_FILE naming its workload identityconfig, exit 1, HTTP 503tests/secrets/scoping/scoped.mjs::a_skarbiec_read_without_a_workload_identity_is_named
scoped-service-not-writablewriting the credentials of service {service}Weles writes only a service that declares the kind its item is stored as, and this one declares noneservice {service} declares no kinddeclare the kind of {service}'s item in src/secrets/scoped-service/catalog/services.json, or write it outside Welesconfig, exit 1, HTTP 503tests/secrets/scoping/scoped.mjs::a_service_weles_does_not_write_is_refused
scoped-write-shapewriting the credentials of service {service}a write carries exactly the fields the catalog declares for the service, and this one carries others, fewer or noneit carries {carried}; the service declares {fields}pass every declared field and no other to the writeconfig, exit 1, HTTP 503tests/secrets/scoping/scoped.mjs::a_write_with_other_fields_is_refused
scoped-value-invalidwriting field {field} of service {service}a field holds text that is not blank and carries no NUL character, and this value is blank, carries a NUL or is not textthe value is {shape}pass the credential the provider issued as non-blank textconfig, exit 1, HTTP 503tests/secrets/scoping/scoped.mjs::a_blank_value_is_refused
scoped-write-refused`stado {command}` writing the credentials of service {service}Stado ran and refused the write in its own words below (every written value redacted): the vault is locked or absent, or this host's Stado may not write the roleexit {status}: {answer}correct what Stado names (`stado credentials doctor` says whether a key opens the vault), then run the trajectory againrefused, exit 1, HTTP 403tests/secrets/scoping/scoped.mjs::a_write_stado_refuses_quotes_stado_redacted
managed-contract-unreadablereading field {field} of the managed credential {secret}no acquisition contract of this release lets Weles read that field of it: {why}the contract of {secret}: {contract}read the field the contract names, or declare the credential in WELES_MANAGED_PASSWORD_CONTRACTS_FILE with its readerconfig, exit 1, HTTP 503tests/secrets/scoping/scoped-contract-failures.mjs::a_managed_field_no_contract_reads_is_refused
managed-reader-mismatchreading field {field} of the managed credential {secret} for tenant {tenant}the grant catalog in force grants this reader the item on another field or tenant, so the read would be refused as nothing granted{mismatch}align the reader grant of the item in the grant catalog with the contract, then run againconfig, exit 1, HTTP 503tests/secrets/scoping/scoped-contract-failures.mjs::a_managed_read_the_catalog_grants_otherwise_is_named
pinned-reference-invalidreading the proxy login an account pin namesthe pin's credential_ref is no lowercase hexadecimal reference, so no field of weles-account-proxy-credentials is named by itcredential_ref of {length} characters, beginning {head}; nothing was readpin the account again; the pin writes the reference of the proxy login it storesconfig, exit 1, HTTP 503tests/secrets/scoping/scoped-contract-failures.mjs::a_pin_reference_that_is_no_hexadecimal_is_refused
binding-tenant-invalidfinding tenant {tenant}'s Skarbiec bindinginvalid Weles tenant id for Skarbiec binding: {tenant} is not a UUID, so it names no directory Stado lays outtenant {tenant}name the tenant by the UUID Stado's binding directory under ~/.stado/weles-skarbiec-tenants carriesconfig, exit 1, HTTP 503tests/secrets/scoping/binding-failures.mjs::a_tenant_that_is_no_uuid_is_refused
binding-unsafereading the Skarbiec {label} {path}refusing unsafe Skarbiec {label}: {path} must be a {kind} only its owner can use, and it {reason}{path}: {reason}make it owned by the account the worker runs as and readable by it alone (`chmod 600 {path}` for a file, `chmod 700 {path}` for a directory), or have Stado issue it again (`stado credentials token mint`)config, exit 1, HTTP 503tests/secrets/scoping/binding-failures.mjs::a_token_file_others_can_read_is_refused
binding-uninspectedreading the Skarbiec {label} {path}the system refused to read the metadata of {path} ({errno}), so whether only its owner can use it is unknown{path}: {errno}; system: {answer}give the account the worker runs as access to the directories above {path} (`ls -ld {path}`), then try againconfig, exit 1, HTTP 503tests/secrets/scoping/binding-failures.mjs::a_token_file_under_a_closed_directory_is_named
binding-absentreading the Skarbiec {label} {path}{path} does not exist: Stado lays out a tenant's binding when the tenant is bound to this worker{path} is absent`stado credentials token mint` for the tenant issues its bearer into the binding again; `ls -l {path}` shows what is thereconfig, exit 1, HTTP 503tests/secrets/scoping/binding-failures.mjs::a_tenant_without_its_binding_directory_is_named
acquired-target-uncontractedwriting {secret}/{field} to the vault for {operation} request {request}no acquisition contract of this release admits that item and field: {why}the contract of {secret}: {contract}; nothing was writtendeclare it in WELES_MANAGED_PASSWORD_CONTRACTS_FILE (a password) or write one of the fields the contract namesconfig, exit 1, HTTP 503tests/secrets/acquiring/acquired-write-failures.mjs::a_write_no_contract_admits_is_refused
acquired-value-unshapedwriting {secret}/{field} to the vault for {operation} request {request}the value lacks the shape the contract admits ({shape}: {expected}), so it is not the credential the provider issuesa value of {bytes} bytes; it is not shown; nothing was writtencapture the credential the provider shows again, or generate the password with the vault policy (`weles errors show identity` names its length)refused, exit 1, HTTP 403tests/secrets/acquiring/acquired-write-failures.mjs::a_value_of_another_shape_is_refused
acquired-request-unnamedwriting {secret}/{field} to the vault for {operation} request {request}the write names no request id of 64 hexadecimal digits, and Skarbiec records every write against the credential operation's requestrequest id {given}; nothing was writtenstart the run as a credential operation, whose constraints carry request_id, then run againconfig, exit 1, HTTP 503tests/secrets/acquiring/acquired-write-failures.mjs::a_write_without_a_request_id_is_refused
acquired-operation-unknownwriting {secret}/{field} to the vault for {operation} request {request}the write names no operation a credential is written foroperation {operation}; a write is one of {operations}; nothing was writtenstart the run with one of {operations} as its constraints' operationconfig, exit 1, HTTP 503tests/secrets/acquiring/acquired-write-failures.mjs::a_write_for_an_unknown_operation_is_refused
acquired-operation-password-onlywriting {secret}/{field} to the vault for {operation} request {request}{operation} writes a password whose predecessor Weles did not know, and {secret} is no password: its contract has shape {shape}operation {operation} for a {shape} contract; nothing was writtenacquire or rotate {secret} instead, or declare it as a managed password in WELES_MANAGED_PASSWORD_CONTRACTS_FILEconfig, exit 1, HTTP 503tests/secrets/acquiring/acquired-write-failures.mjs::a_reset_of_a_token_is_refused
acquired-value-not-utf8writing {secret}/{field} to the vault for {operation} request {request}the vault keeps text fields, and the value stops being UTF-8 text at byte {offset}a value of {bytes} bytes, valid UTF-8 up to byte {offset}; it is not shown; nothing was writtencapture the credential as the text the provider shows, not its bytesrefused, exit 1, HTTP 403tests/secrets/acquiring/acquired-write-failures.mjs::a_value_that_is_not_utf8_is_refused
acquired-origin-unstatedwriting {secret}/{field} to the vault for {operation} request {request}the write claims no exact https origin the value was captured on ({from}), and Skarbiec records that provenance with every writecaptured origin {origin}; nothing was writtencapture the value on the provider page, or state secret_source_origin as the bare https origin (https://host, no path or trailing slash)config, exit 1, HTTP 503tests/secrets/acquiring/acquired-write-failures.mjs::a_write_without_its_origin_is_refused
acquired-origin-otherwriting {secret}/{field} to the vault for {operation} request {request}the value was captured on another origin than the signup origin Skarbiec recorded for the operation, so Skarbiec would refuse the write as another provenancecaptured on {captured}; the operation declared {declared}; nothing was writtencapture the credential on {declared}, or start a new operation declaring {captured}refused, exit 1, HTTP 403tests/secrets/acquiring/acquired-write-failures.mjs::a_value_captured_on_another_origin_is_refused
acquired-account-email-invalidwriting {secret}/{field} to the vault for {operation} request {request}a password is written as the login of one account, and the write names no valid account emailaccount email {email}; nothing was writtenstart the operation with account_email set to the address the account signs in withconfig, exit 1, HTTP 503tests/secrets/acquiring/acquired-write-failures.mjs::a_password_without_its_account_is_refused
acquired-writer-token-unissuedwriting {secret}/{field} to the vault for {operation} request {request} through Skarbiec at {route}Stado never issued the scoped writer token file {file} of consumer {consumer}, so this host may not write {item}no file {file} in {where}; nothing was writtenissue the writer grant of {consumer} for {item} on this host (`stado credentials doctor` names what it holds), then run againconfig, exit 1, HTTP 503tests/secrets/acquiring/acquired-write-failures.mjs::a_write_without_its_writer_token_is_named
acquired-helper-unstartedwriting {secret}/{field} to the vault for {operation} request {request} through the write helper {helper}the write helper could not be started ({errno}): the release lacks it, or SKARBIEC_WELES_WRITER_COMMAND names a file that is not there`{command}` in {directory}: {problem}; nothing was writteninstall the Weles release whose src/worker/deploy/acquire carries skarbiec-write.mjs (`stado product install weles --surface cli`), or correct SKARBIEC_WELES_WRITER_COMMANDconfig, exit 1, HTTP 503tests/secrets/acquiring/acquired-write-failures.mjs::a_write_helper_that_cannot_start_is_named
acquired-helper-unavailablewriting {secret}/{field} to the vault for {operation} request {request} through Skarbiec at {route}the write helper could not reach Skarbiec or Stado, and says a later try may succeed`{command}` in {directory} exited {status}: cause {helper_cause}: {said}; its fix: {helper_fix}{helper_fix}; then run againinfra_down, exit 69, HTTP 503, retryabletests/secrets/acquiring/acquired-write-failures.mjs::a_write_skarbiec_cannot_take_now_is_named
acquired-helper-refusedwriting {secret}/{field} to the vault for {operation} request {request} through Skarbiec at {route}the write helper declared why Skarbiec did not take the write (its cause below): the grant, the item or the payload`{command}` in {directory} exited {status}: cause {helper_cause}: {said}; its fix: {helper_fix}{helper_fix}; `weles errors show skarbiec` lists the helper's causesrefused, exit 1, HTTP 403tests/secrets/acquiring/acquired-write-failures.mjs::a_write_skarbiec_refuses_is_named
acquired-helper-unenvelopedwriting {secret}/{field} to the vault for {operation} request {request} through Skarbiec at {route}the write helper {ended} without its declared JSON answer on standard error: it crashed, was killed, or is of another release`{command}` in {directory} {ended}; it said: {said} (the value redacted wherever it appears)run the helper of this release (`stado product install weles --surface cli`), and read what it said aboveunknown, exit 1, HTTP 500tests/secrets/acquiring/acquired-write-failures.mjs::a_write_helper_that_answers_nothing_is_named
read-value-not-line{what}the reader printed no single line of text where a field value is one: it printed nothing, several lines or a NUL{lines} lines, {bytes} bytes; the value is not shownstore the field as one line of text (`stado credentials put`), or run the reader of this release (`stado product install weles --surface cli`)unknown, exit 1, HTTP 500tests/secrets/acquired-read-failures.mjs::a_read_that_prints_no_line_is_named
role-read-unstartedreading field {field} of the item playing role {role} as consumer {consumer}Stado could not be started ({errno}), so no grant was presented`{command}` in {directory}: {problem}install Stado (`stado --version` must answer) or set WELES_STADO_BIN to its program, then run againconfig, exit 1, HTTP 503tests/secrets/acquired-read-failures.mjs::a_role_read_stado_cannot_start_is_named
role-read-refusedreading field {field} of the item playing role {role} as consumer {consumer}Stado refused the read in its own words below: the consumer's grant does not reach the role or field, the grant file is another consumer's, or Skarbiec was not reached`{command}` in {directory} {ended}: {said}grant {consumer} read:role:{role}#{field} (`stado credentials doctor` says what this host holds), then run againrefused, exit 1, HTTP 403tests/secrets/acquired-read-failures.mjs::a_role_read_stado_refuses_is_named
acquisition-helper-unstartedacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}the acquisition helper {helper} could not be started ({errno}): the release lacks it, or SKARBIEC_WELES_READER_ACQUIRE_COMMAND names a file that is not there`{command}` in {directory}: {problem} {record}install the Weles release whose src/worker/deploy/acquire carries skarbiec-acquire.mjs (`stado product install weles --surface cli`), or correct SKARBIEC_WELES_READER_ACQUIRE_COMMANDconfig, exit 1, HTTP 503tests/secrets/acquired-read-failures.mjs::an_acquisition_helper_that_cannot_start_is_named
acquisition-helper-unenvelopedacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}the acquisition helper {ended} without its declared JSON answer on standard error: it crashed, was killed, or is of another release`{command}` in {directory} {ended}; it said: {said} {record}run the helper of this release (`stado product install weles --surface cli`), and read what it said aboveunknown, exit 1, HTTP 500tests/secrets/acquired-read-failures.mjs::an_acquisition_helper_that_answers_nothing_is_named
acquisition-route-refusedacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}the helper could not find Skarbiec through the secrets alternative, so the vault was never asked`{command}` in {directory} {ended}: cause {helper_cause}: {said}; its fix: {helper_fix} {record}{helper_fix}; then run againinfra_down, exit 69, HTTP 503, retryabletests/secrets/acquired-read-failures.mjs::an_acquisition_without_a_route_is_named
acquisition-scope-undeclaredacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}the deployment's acquisition scopes declare no line for this consumer, item and field, so the helper asks Skarbiec nothing`{command}` in {directory} {ended}: cause {helper_cause}: {said}; its fix: {helper_fix} {record}{helper_fix}config, exit 1, HTTP 503tests/secrets/acquired-read-failures.mjs::an_acquisition_of_an_undeclared_scope_is_named
acquisition-authority-unreachableacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}Skarbiec did not answer the helper: it is down, or the address the secrets alternative names does not reach it`{command}` in {directory} {ended}: cause {helper_cause}: {said}; its fix: {helper_fix} {record}{helper_fix}; then run againinfra_down, exit 69, HTTP 503, retryabletests/secrets/acquired-read-failures.mjs::an_acquisition_skarbiec_does_not_answer_is_named
acquisition-workload-unauthorizedacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}Skarbiec does not admit the run's workload identity for this consumer: it is unregistered, or its signing key is another workload's`{command}` in {directory} {ended}: cause {helper_cause}: {said}; its fix: {helper_fix} {record}{helper_fix}auth, exit 1, HTTP 401tests/secrets/acquired-read-failures.mjs::an_acquisition_of_an_unadmitted_workload_is_named
acquisition-grant-endedacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}the consumer's grant on the item ended: its window closed or it was revoked`{command}` in {directory} {ended}: cause {helper_cause}: {said}; its fix: {helper_fix} {record}{helper_fix}refused, exit 1, HTTP 403tests/secrets/acquired-read-failures.mjs::an_acquisition_whose_grant_ended_is_named
acquisition-field-absentacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}Skarbiec holds the item without that field: the credential was never written with it`{command}` in {directory} {ended}: cause {helper_cause}: {said}; its fix: {helper_fix} {record}{helper_fix}not_found, exit 1, HTTP 404tests/secrets/acquired-read-failures.mjs::an_acquisition_of_an_absent_field_is_named
acquisition-refusedacquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}Skarbiec refused the acquisition for a reason the helper names in its own cause below`{command}` in {directory} {ended}: cause {helper_cause}: {said}; its fix: {helper_fix} {record}{helper_fix}refused, exit 1, HTTP 403tests/secrets/acquired-read-failures.mjs::an_acquisition_skarbiec_refuses_is_named
acquisition-cause-otheracquiring {coordinate}/{field} as consumer {consumer} from Skarbiec at {route}the helper declared a cause of skarbiec.acquisition this release does not know: it is of a newer release`{command}` in {directory} {ended}: cause {helper_cause}: {said}; its fix: {helper_fix} {record}{helper_fix}; run a helper and reader of the same release (`stado product install weles --surface cli`)unknown, exit 1, HTTP 500tests/secrets/acquired-read-failures.mjs::an_acquisition_cause_this_release_does_not_know_is_named
job-contract-absentbuilding the {provider} job that acquires {secret}the release's acquisition registry names {secret}, which no contract of the same release holds: the registry and the contract table disagreedefinition {secret} of provider {provider}, flow {flow}; nothing was queuedinstall one consistent Weles release (`stado product install weles --surface cli`)unknown, exit 1, HTTP 500tests/secrets/acquiring/acquisition-job-failures.mjs::a_job_for_an_uncontracted_definition_is_named
job-coordinate-absentbuilding the {provider} job that acquires {secret}the job must name {what} to bind the run to one exact identity, and the request carries none{what}: {given}; nothing was queuedsend the request again with {what}config, exit 1, HTTP 503tests/secrets/acquiring/acquisition-job-failures.mjs::a_job_without_its_identity_is_named
job-item-unconstrainedbuilding the {provider} job that acquires {secret}the job this release built names no vault item in constraints.vault_item_id, so the run could not store what it acquiresconstraints {constraints}; nothing was queuedinstall one consistent Weles release (`stado product install weles --surface cli`)unknown, exit 1, HTTP 500tests/secrets/acquiring/acquisition-job-failures.mjs::a_job_without_its_item_is_named
catalog-schema-undeclaredreading the service catalog src/secrets/scoped-service/catalog/services.jsonservice {service} names schema {schema}, which the same catalog does not declare: the catalog was edited inconsistentlythe catalog declares schemas {schemas}declare schema {schema} in services.json, or install one consistent Weles release (`stado product install weles --surface cli`)unknown, exit 1, HTTP 500tests/secrets/acquiring/acquisition-job-failures.mjs::a_catalog_service_of_an_undeclared_schema_is_named
answer-unstatedreading what the credential operation run stated in {where}the file holds no credential_operation object, the one place a run states what it did to the credential: the run ended before stating it, or is of another release{where} holds {found}read the run's log and recordings (`weles runs show <run-id>`) for where it stopped, then run the operation againunknown, exit 1, HTTP 500tests/secrets/acquiring/operation-answer-failures.mjs::an_answer_without_its_object_is_named
answer-incompletereading what the credential operation run stated in {where}the credential_operation object states no {member}, which every answer carries{member}: {found}; it states {members}run a trajectory of this release, which states status, message and providerEffect (`stado product install weles --surface cli`)unknown, exit 1, HTTP 500tests/secrets/acquiring/operation-answer-failures.mjs::an_answer_without_a_member_is_named
followup-count-unstatedreading the Semantic Scholar key mail for submission {source}{name} states {what} as no whole number above zero, and Weles assumes none{name}: {value}set {name} to a whole number above zero in the Weles service environment (`stado service env set weles`)config, exit 1, HTTP 503tests/secrets/semantic-scholar-followup-failures.mjs::a_followup_without_its_counts_is_refused
followup-contract-absentreading the Semantic Scholar key mail for submission {source}the key was stored, and this release holds no contract of semantic_scholar.api_key to say where: the contract table and the follow-up disagreekey stored from mail {email}; no contract to name its iteminstall one consistent Weles release (`stado product install weles --surface cli`)unknown, exit 1, HTTP 500tests/secrets/semantic-scholar-followup-failures.mjs::a_followup_without_its_contract_is_named
followup-validation-unansweredasking {url} whether a key found in the mail is validthe Semantic Scholar API could not be reached ({errno}): the network or its address failed, so the candidate was neither accepted nor rejected{problem}; {scanned} mails read so far; the candidate is not shownrun the follow-up again once https://api.semanticscholar.org answersinfra_down, exit 69, HTTP 503, retryabletests/secrets/semantic-scholar-followup-failures.mjs::a_validation_the_api_does_not_answer_is_named

runtime#

5 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
cost-run-unsetkeeping the cost records of this runACTION_LOG_ID is not set, so the {count} cost records of this run have no rollup file to go to{count} records held in memory, {usd} USD; ACTION_LOG_ID unsetrun it through the Weles worker, which sets ACTION_LOG_ID for every run it startsconfig, exit 1, HTTP 503tests/runtime/cost-run-failures.mjs::a_run_without_its_log_id_names_its_costs
cost-rollup-unreadablekeeping the cost records of run {run} in {path}the rollup file exists and cannot be read ({errno}), so it is not overwritten{path}: {problem}give the worker's user read and write access to {path}, then run againconfig, exit 1, HTTP 503tests/runtime/cost-failures.mjs::a_rollup_that_cannot_be_read_is_named
cost-rollup-not-jsonkeeping the cost records of run {run} in {path}the rollup file is not JSON, so it is not overwritten{bytes} bytes; the parser said: {problem}move {path} aside (it holds the run's earlier costs) and run againconfig, exit 1, HTTP 503tests/runtime/cost-failures.mjs::a_rollup_that_is_not_json_is_named
cost-rollup-shapekeeping the cost records of run {run} in {path}the rollup file is JSON without cost_usd and service_costs, so it is no cost rollup and is not overwrittenmembers: {members}move {path} aside (it is some other file) and run againconfig, exit 1, HTTP 503tests/runtime/cost-failures.mjs::a_rollup_of_another_shape_is_named
cost-rollup-unwrittenkeeping the cost records of run {run} in {path}the recordings directory refused the rollup ({errno}): it is not writable by the worker user, or its disk is full{path}: {problem}give the worker's user write access to {directory} and free space on its diskconfig, exit 1, HTTP 503tests/runtime/cost-failures.mjs::a_rollup_the_directory_refuses_is_named

human#

2 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
timing-unseededdrawing human timing for {use}human timing was drawn before any session seeded it (seedHumanTiming runs at session start); the run would not be reproducible from its recorded seedseedHumanTiming has not run in this process (pid {pid})start a WSession (or call seedHumanTiming with the run's seed) before the pointer or keyboard movesunknown, exit 1, HTTP 500tests/human/timing-failures.mjs::a_draw_before_any_seed_is_refused
timing-count-invaliddrawing one of {count} choices from the run's seeded timinghumanIndex needs a whole count of choices above zero, and {count} is not onecount {count}pass the number of choices offered, a whole number above zerounknown, exit 1, HTTP 500tests/human/timing-failures.mjs::a_draw_among_no_choices_is_refused

reauth#

20 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
bearer-rejectedadmitting {method} {path}the request carries no Authorization bearer equal to this API's BRAMA_WELES_REAUTH_TOKEN: it carries the general API token, another deployment's bearer, or one rotated after it was reada request without the reauth bearersend the token of the item playing brama-weles-reauth as the bearer (`stado credentials get --role brama-weles-reauth --field token`)auth, exit 1, HTTP 401tests/reauth/failures.mjs::a_route_without_the_reauth_bearer_is_refused
token-unsetadmitting {method} {path}this API was started without BRAMA_WELES_REAUTH_TOKEN, so no bearer can be admitted to its account routes: it was run outside its unit, whose launcher acquires the tokenBRAMA_WELES_REAUTH_TOKEN: not setstart the API through its unit (`stado service ensure weles --host <this host> --reason <why>`), whose launcher acquires BRAMA_WELES_REAUTH_TOKENconfig, exit 1, HTTP 500tests/reauth/failures.mjs::an_api_started_without_the_reauth_token_names_it
provider-unsupportedadmitting {method} {path}the body names a provider this Weles holds no {trajectory} trajectory for (src/trajectories/<provider>/{trajectory}.mjs), or names noneprovider: {provider}name one of the providers this route serves: {providers}refused, exit 1, HTTP 400tests/reauth/failures.mjs::a_provider_without_a_sign_in_is_refused
subscription-missingadmitting {method} {path}the body names no subscription_id, and the route acts on exactly one subscription of the vaultsubscription_id: not givensend subscription_id: the subscription id `weles accounts list` (or POST /reauth/accounts) showsrefused, exit 1, HTTP 400tests/reauth/failures.mjs::a_sign_in_naming_no_subscription_is_refused
account-revision-changedadmitting {method} {path}the account_revision the caller resolved differs from the revision the vault holds now: the subscription or its login was rewritten after the caller read itasked for revision {asked}; the vault holds {account_revision}resolve the account again (POST /reauth/resolve) and send the revision it answersrefused, exit 1, HTTP 409tests/reauth/failures.mjs::a_sign_in_for_an_account_that_changed_is_refused
run-unstartedrunning {trajectory} of {provider} on this hostthe worker could not start the run once admitted: its process could not be spawned (no process slots, the trajectory program unreadable) or its progress could not be recorded{answer}run `weles doctor` on the Weles host for what it lacks, then ask for the run again; `weles worker version` names the releaseinfra_down, exit 69, HTTP 200, retryabletests/reauth/failures.mjs::a_run_the_worker_cannot_start_is_named
run-record-unwritablerecording the {trajectory} run of {provider} before it startsthe worker cannot write the run's result file, so the run is not started: the run results directory is missing, not writable by the worker's user, or its disk is full{path}: {answer}make the run results directory writable for the user the Weles unit runs as (`weles doctor` names it), then ask for the run againconfig, exit 1, HTTP 200tests/reauth/failures.mjs::a_run_whose_record_cannot_be_written_is_named
sign-in-cancelledsigning {provider} account in, run {run}the run was cancelled before it ended, so no grant was takencancelled at stage {stage}: {message}ask for the sign-in again once whatever cancelled it is settled; `weles runs show {run}` shows the run's stages and the end of its outputinfra_down, exit 69, HTTP 200, retryabletests/reauth/outcome-failures.mjs::a_sign_in_cancelled_while_it_runs_is_named
sign-in-report-unreadablereading why sign-in run {run} of {provider} failedthe run's AUTH_FAILURE line is not the JSON object of code, stage and message a sign-in trajectory writes, so why it failed is unknown{message}compare `weles worker version` with the release the trajectory came from; `weles runs show {run}` shows the run's stages and the end of its outputrefused, exit 1, HTTP 200tests/reauth/outcome-failures.mjs::a_sign_in_whose_failure_line_cannot_be_read_is_named
sign-in-acquisition-refusedreading field {field} of vault item {item} for sign-in run {run} of {provider}the vault refused the run the item it signs in with ({reason})item {item}, field {field}, consumer {consumer}, at stage {stage}grant consumer {consumer} field {field} of item {item} in the vault, or name another login; `stado credentials ls` lists what the store holdsrefused, exit 1, HTTP 200tests/reauth/outcome-failures.mjs::a_sign_in_the_vault_refuses_its_login_is_named
sign-in-unreportedsigning {provider} account in, run {run}the run ended without a grant and without an AUTH_FAILURE line or vault acquisition record saying why: it was killed, or crashed before it could reportlast stage {stage}; exit {exit}read the end of the run's output: `weles runs show {run}` shows the run's stages and the end of its outputrefused, exit 1, HTTP 200tests/reauth/outcome-failures.mjs::a_sign_in_that_ends_without_saying_why_is_named
sign-in-undeclaredsigning {provider} account in, run {run}, at stage {stage}the trajectory met an error no declared cause names, so only its own words say what broke{message}`weles runs show {run}` shows the run's stages and the end of its output; the error is a defect of the trajectory to declarerefused, exit 1, HTTP 200tests/reauth/outcome-failures.mjs::a_sign_in_failing_on_an_undeclared_error_is_named
run-result-missingreading the result of {trajectory} run {run} of {provider}the run ended without printing its result line: the trajectory exited before answering, which is a defect of that trajectoryexit {exit}; last output: {tail}run `weles runs show {run}` for what the run saw, and report it with `weles worker version`config, exit 1, HTTP 200tests/reauth/failures.mjs::a_run_that_prints_no_result_is_named
acquire-unsupportedadmitting the purchase of a {provider} accountWeles has no src/trajectories/{provider}/account/acquire.mjs, so it cannot buy an account of that providerprovider: {provider}; it buys accounts of {providers}name a provider Weles buys accounts of: {providers}refused, exit 1, HTTP 400tests/reauth/failures.mjs::a_purchase_of_a_provider_weles_cannot_buy_is_refused
acquisition-incompleteadmitting the purchase of a {provider} accounta purchase names the correlation subscription_id, the plan_tier to buy and the reason, and the body lacks somemissing: {missing}send subscription_id, plan_tier and reason as non-empty textrefused, exit 1, HTTP 400tests/reauth/failures.mjs::a_purchase_lacking_its_plan_is_refused
authorization-incompletereading the authorization {path} is asked to completean authorization names a provider with an authorize page, a subscription_id and an authorize_url, and the body lacks oneprovider: {provider}; subscription_id: {subscription}; authorize_url: {url}send provider (one of {providers}), subscription_id and the authorize_url the harness printedrefused, exit 1, HTTP 400tests/reauth/failures.mjs::an_authorization_lacking_its_url_is_refused
authorize-url-invalidreading the authorization {path} is asked to completeauthorize_url, or the redirect_uri it carries, is not an absolute URL, so it names no page to drive{what}: {url}send the authorize_url exactly as the harness printed itrefused, exit 1, HTTP 400tests/reauth/failures.mjs::an_authorize_url_that_is_not_a_url_is_refused
authorize-page-foreignreading the authorization {path} is asked to completeauthorize_url is not the provider's own authorize page, and Weles drives no other page with the accountauthorize_url is {page}; the {provider} authorize page is {expected}send the authorize_url the provider's own login printed for this harnessrefused, exit 1, HTTP 400tests/reauth/failures.mjs::an_authorization_on_another_page_is_refused
authorize-redirect-missingreading the authorization {path} is asked to completeauthorize_url carries no redirect_uri, so the code the provider issues could not go back to the harness that askedauthorize_url: {url}send the whole authorize_url the harness printed, with its redirect_urirefused, exit 1, HTTP 400tests/reauth/failures.mjs::an_authorization_without_a_redirect_is_refused
authorize-redirect-foreignreading the authorization {path} is asked to completeredirect_uri sends the code somewhere other than the harness's own localhost listener, and Weles answers a redirect to that listener onlyredirect_uri goes to {host}start the authorization from the harness on the machine that will hold the grant, and send its authorize_urlrefused, exit 1, HTTP 400tests/reauth/failures.mjs::an_authorization_redirecting_elsewhere_is_refused

Admission#

How POST /api/v1/tasks, GET /api/v1/tasks/<task-id> and POST /api/v1/tasks/<task-id>/cancel refuse a request. The answer keeps the error code a caller branches on and adds message (what failed, why, observed), cause, remedy, retryable and docs.

100 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
bearer-missingauthenticating {method} {path}the request carries no Authorization: Bearer header, and every public task route takes the Spis admission bearerAuthorization: {authorization}send Authorization: Bearer <token>, the token field of the Skarbiec item weles-spis-public-admission this worker was started withauth, exit 1, HTTP 401tests/admission/request-failures.mjs::submit_refuses_a_request_without_a_bearer
bearer-wrongauthenticating {method} {path}the bearer is not the one this worker admits: it belongs to another deployment, or the item was rotated after the caller read ita bearer of {length} characters that does not match WELES_PUBLIC_API_BEARERread the token field of the Skarbiec item weles-spis-public-admission again and send it; if it was rotated, restart the worker so it reads the new oneauth, exit 1, HTTP 401tests/admission/request-failures.mjs::submit_refuses_a_bearer_this_worker_does_not_admit
media-type-missingreading the body of {method} {path}the request states no Content-Type, and a public task body is read only as application/jsonContent-Type: nonesend the body with the header Content-Type: application/jsonrefused, exit 1, HTTP 415tests/admission/request-failures.mjs::submit_refuses_a_body_without_content_type
media-type-wrongreading the body of {method} {path}the request states a Content-Type other than application/jsonContent-Type: {media_type}send the body as JSON with the header Content-Type: application/jsonrefused, exit 1, HTTP 415tests/admission/request-failures.mjs::submit_refuses_a_body_of_another_media_type
idempotency-key-missingreading the Idempotency-Key of {method} {path}the request carries no Idempotency-Key header, so a retry could not be told from a new requestIdempotency-Key: nonesend an Idempotency-Key header of letters, digits, _, ., : or -, the same one each time the same request is retriedrefused, exit 1, HTTP 400tests/admission/request-failures.mjs::submit_refuses_a_request_without_an_idempotency_key
idempotency-key-invalidreading the Idempotency-Key of {method} {path}the Idempotency-Key holds a character other than letters, digits, _, ., : or -Idempotency-Key: {key}send a key of only those characters, such as a UUIDrefused, exit 1, HTTP 400tests/admission/request-failures.mjs::submit_refuses_an_idempotency_key_with_other_characters
body-not-jsonreading the body of {method} {path}the body is not a JSON document (invalid_json), so the task it asks for cannot be read{bytes} bytes; the parser said: {answer}send one JSON object as the bodyrefused, exit 1, HTTP 400tests/admission/request-failures.mjs::submit_refuses_a_body_that_is_not_json
organization-deniedadmitting a task for organization {organization}the bearer authenticates one tenant and the request names another organizationorganizationId: {organization}send the organization_id field of the Skarbiec item weles-spis-public-admission as organizationIdrefused, exit 1, HTTP 403tests/admission/request-failures.mjs::submit_refuses_another_organization
task-id-invalidreading the task id in {path}a task id is the UUID the submission answered as taskIdtask id: {task_id}use the taskId of the submission answerrefused, exit 1, HTTP 400tests/admission/records/record-failures.mjs::status_refuses_a_task_id_that_is_not_a_uuid
task-not-foundreading public task {task_id}this worker holds no task of that id: it was submitted to another worker, or its state was removedno task-{task_id}.json under {root}read the task from the worker that answered its submission (its serviceIdentity names the host)not_found, exit 1, HTTP 404tests/admission/records/record-failures.mjs::status_refuses_a_task_this_worker_never_held
worker-recoveringadmitting a public taskthe worker is recovering its durable task state, or its last recovery failed and left admission pauseddispatcher: {dispatcher}read GET /worker/status for the recovery failure, repair the state it names under the run results directory, then POST /worker/restartinfra_down, exit 69, HTTP 503, retryabletests/admission/identities/deployment-failures.mjs::submit_refuses_while_recovery_failed
prerequisites-not-readyadmitting a public taska prerequisite the deployment must state is missing: a release version, digest or source revision, the generic_browser_task trajectory, or the artifact store (STADO_API_URL and WELES_STADO_OBJECT_API_TOKEN)prerequisites: {prerequisites}start the worker through its release launcher with the Stado object store declared for it; GET /api/v1/version lists which prerequisite is falseconfig, exit 1, HTTP 503tests/admission/identities/deployment-failures.mjs::submit_refuses_when_the_artifact_store_is_not_declared
service-drainingadmitting a public taskthe worker received a termination signal and stops admitting work while its running tasks settlethe service is draining after a termination signalsend the task again once the worker has restarted; GET /api/v1/version answers ready: true when it admits workinfra_down, exit 69, HTTP 503, retryabletests/admission/identities/deployment-failures.mjs::submit_refuses_while_the_worker_drains
task-schema-unsupportedreading the taskthe body is not an object whose schema is {expected}schema: {schema}send a task object with "schema": "{expected}"refused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_a_task_of_another_schema
json-number-unsafereading {path}it holds a number that is not a safe integer (a fraction, or beyond 2^53 - 1), which canonical public JSON does not carry{path} = {value}send that value as a whole number within 2^53 - 1, or as a stringrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_a_number_that_is_not_a_safe_integer
json-lone-surrogatereading {path}a string or key holds a lone UTF-16 surrogate, which is not text and has no canonical encodingthe lone surrogate is in {path}send the text as valid Unicode: encode the character whole, or drop the stray halfrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_a_lone_utf16_surrogate
task-fields-undeclaredreading the taskits fields are not exactly the ones {schema} declares{reasons}send exactly the fields {declared}; a credential enters a task only as a reference in credentialRefsrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_a_task_with_undeclared_or_missing_fields
origin-invalidreading the task originorigin is not an exact HTTPS origin (scheme and host, no path, no trailing slash)origin: {origin}; {answer}send origin as https://<host>, for example the origin of input.product_urlrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_an_origin_that_is_not_https
origin-deniedadmitting a task for origin {origin}the origin is not in the service policy WELES_PUBLIC_API_ALLOWED_ORIGINSallowed origins: {allowed}send a task for an allowed origin, or add the origin to WELES_PUBLIC_API_ALLOWED_ORIGINS in the worker unit and restart itrefused, exit 1, HTTP 403tests/admission/tasks/task-failures.mjs::submit_refuses_an_origin_the_policy_does_not_allow
action-deniedadmitting a task for action {action}the public API runs only the action {allowed}action: {action}send "action": "{allowed}"; other actions run through the operator API, not the public onerefused, exit 1, HTTP 403tests/admission/tasks/task-failures.mjs::submit_refuses_an_action_the_policy_does_not_allow
input-not-objectreading task.inputinput is not a JSON objectinput: {input}send input as an object holding product_url, objective, constraints and spisBindingrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_an_input_that_is_not_an_object
input-fields-undeclaredreading task.inputits fields are not exactly the ones the task schema declares for input{reasons}send exactly the fields {declared}refused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_an_input_with_undeclared_fields
product-url-invalidreading input.product_urlit is not an exact canonical public HTTPS URL without credentialsproduct_url: {url}; {answer}send the page as https://<host>/<path>, written as new URL() writes it (lowercase host, a path of at least /), with no user or passwordrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_a_product_url_that_is_not_canonical_https
origin-target-mismatchadmitting a task for {url}the task origin is not the origin of the page it asks the browser to openorigin {origin}, page origin {target}send origin equal to the origin of input.product_urlrefused, exit 1, HTTP 403tests/admission/tasks/task-failures.mjs::submit_refuses_a_page_outside_the_task_origin
objective-emptyreading input.objectiveobjective is not a non-empty string, so the run would have nothing to doobjective: {objective}send one sentence saying what the browser should record on the pagerefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_an_empty_objective
constraints-mismatchreading input.constraintsthe constraints are not exactly the browser-evidence policy {policy} this worker enforcessent {constraints}; the policy states {expected}send input.constraints as exactly {expected}; GET /api/v1/version names the policy and its digestrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_constraints_other_than_the_policy
spis-binding-not-objectreading input.spisBindingspisBinding is not a JSON objectspisBinding: {value}send the binding Spis issued for the crawl attempt as an object of schema weles.spis-browser-evidence-binding.v1refused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_binding_that_is_not_an_object
spis-binding-fieldsreading input.spisBindingits fields are not exactly the ones weles.spis-browser-evidence-binding.v1 declaresundeclared: {undeclared}; missing: {missing}send exactly the fields {declared}refused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_binding_with_missing_fields
spis-binding-schemareading input.spisBindingits schema is not weles.spis-browser-evidence-binding.v1schema: {schema}send the binding as Spis writes it for this worker, schema weles.spis-browser-evidence-binding.v1refused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_binding_of_another_schema
spis-binding-attemptreading input.spisBindingattempt is not a whole number from 1 to 4294967295attempt: {attempt}send the attempt number Spis counted for the record, starting at 1refused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_attempt_of_zero
spis-binding-source-revisionreading input.spisBindingsource_revision is not a full lowercase 40-character Git commitsource_revision: {value}send the full commit of the Spis source the crawl ran fromrefused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_source_revision_that_is_not_a_commit
spis-binding-digestreading input.spisBinding{field} is not a lowercase 64-character SHA-256{field}: {value}send the SHA-256 Spis computed, in lowercase hexrefused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_digest_that_is_not_sha256
spis-binding-servicereading input.spisBindingservice is not the exact authorized Weles service identity: weles-admission for consumer spis, capability browser-evidence and action generic_browser_task, with a directory generation, host, release id and source revisionservice: {value}send the service identity GET /api/v1/version answers as serviceIdentity, with its generation as directory_generation and its active_host as hostrefused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_service_of_another_capability
spis-binding-endpointreading input.spisBindingservice.endpoint is not the exact absolute /api/v1 base URL, with no credentials, query or fragmentservice.endpoint: {value}send the endpoint GET /api/v1/version answers in serviceIdentityrefused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_endpoint_that_is_not_the_task_api
spis-binding-componentreading input.spisBinding{field} is not one portable path component (letters, digits, ., _ or -, and not . or ..){field}: {value}send the {field} Spis wrote, which is one such componentrefused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_component_that_is_a_path
spis-binding-not-canonicalreading input.spisBindingthe record key, attempt id or artifact URIs are not the ones recomputed from the binding, so the evidence would land on another recordrecord_key {record_key} (expected {expected_record_key}); attempt_id {attempt_id} (expected {expected_attempt_id}); artifact_uri {artifact_uri} (expected {expected_artifact_uri}); output_uri {output_uri} (expected {expected_output_uri})send the binding exactly as Spis computed it; do not edit one field of itrefused, exit 1, HTTP 400tests/admission/identities/binding-failures.mjs::submit_refuses_a_spis_binding_whose_keys_do_not_recompute
credential-refs-invalidreading task.credentialRefscredentialRefs is not an array of non-empty stringscredentialRefs: {value}send "credentialRefs": [] for a browser-evidence taskrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_credential_refs_that_are_not_a_list
credential-refs-deniedadmitting a task that names credentialsa browser-evidence task records a public page and is never handed a credentialcredentialRefs: {value}send "credentialRefs": []; a page behind a sign-in is not public evidencerefused, exit 1, HTTP 403tests/admission/tasks/task-failures.mjs::submit_refuses_a_task_that_names_credentials
evidence-policy-invalidreading task.evidencePolicya browser-evidence task keeps its full evidence, and evidencePolicy says otherwiseevidencePolicy: {value}send "evidencePolicy": "full"refused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_an_evidence_policy_other_than_full
justification-emptyreading task.justificationjustification is not a non-empty string, and every admitted task records why it runsjustification: {value}send one sentence saying why this page is recordedrefused, exit 1, HTTP 400tests/admission/tasks/task-failures.mjs::submit_refuses_an_empty_justification
idempotency-conflictadmitting the task under Idempotency-Key {key}the key was already used for a request with different content, so this is not a retry of itthe key is bound to request digest {bound}; this request digests to {digest}send a new Idempotency-Key for a new request, or resend the original request unchanged to read its taskrefused, exit 1, HTTP 409tests/admission/identities/deployment-failures.mjs::submit_refuses_a_reused_key_for_another_request
service-identity-unreadablereading the deployed Weles service identitythe placement policy, the service-directory snapshot or the admission endpoint Stado publishes on this host could not be read as this release: the identity reader refused with {lower}{answer}{fix}; then send the task again (GET /worker/status names the failure and its cause as serviceIdentityFailure, and `weles errors show admission.service-identity` lists what the reader refuses)config, exit 1, HTTP 503tests/admission/identities/binding-failures.mjs::submit_refuses_when_the_service_identity_is_unpublished
service-identity-mismatchadmitting a task bound to service {bound}spisBinding.service is not the service identity this worker is deployed as: Spis bound the attempt to another host, generation or releasebound {bound}; deployed {deployed}have Spis read GET /api/v1/version again and bind the attempt to the identity it answersrefused, exit 1, HTTP 403tests/admission/identities/binding-failures.mjs::submit_refuses_a_binding_to_another_service_generation
target-unresolvedresolving the page host {host}the host has no DNS answer: it does not exist, or this worker cannot reach a resolver{answer}check the host name in input.product_url; if it resolves elsewhere, check the DNS configuration of the worker hostnot_found, exit 1, HTTP 403tests/admission/identities/deployment-failures.mjs::submit_refuses_a_page_host_without_dns
target-not-publicresolving the page host {host}the host resolves to an address IANA does not declare globally reachable (loopback, private, link-local and the like), and a public task opens only public pages{answer}send a page whose host resolves only to public addresses; a private page is opened through the operator APIrefused, exit 1, HTTP 403tests/admission/identities/deployment-failures.mjs::submit_refuses_a_page_host_on_a_private_address
address-registry-unreadablejudging the addresses of {host}the IANA special-purpose address registries could not be read, so no address can be judged public{answer}let the worker host reach https://www.iana.org/assignments/ (directly or through its HTTPS_PROXY), then send the task againinfra_down, exit 69, HTTP 503, retryabletests/admission/identities/deployment-failures.mjs::submit_refuses_when_the_address_registry_is_unreachable
task-state-unwritablerecording the public task under {root}the worker cannot write its task state: the directory is not writable by the service user, or the disk is full{answer}give the service user write access to {root} and free space on its disk, then send the task again with the same Idempotency-Keyconfig, exit 1, HTTP 500tests/admission/identities/deployment-failures.mjs::submit_refuses_when_task_state_is_unwritable
wait-invalidreading the wait parameter of {path}wait takes only the value terminalwait={wait}send ?wait=terminal to hold the answer until the task ends, or no wait to read it nowrefused, exit 1, HTTP 400tests/admission/records/record-failures.mjs::status_refuses_a_wait_other_than_terminal
task-record-unreadablereading public task {task_id}its record {file} is not one JSON document: the worker writes it whole and renames it into place, so it was truncated or written by something else{answer} (cause {lower})restore {file} from the worker host backup, or remove it so the task reads as not foundconfig, exit 1, HTTP 500tests/admission/records/record-failures.mjs::status_refuses_a_task_record_that_is_not_json
task-record-refusedreading public task {task_id}the system refused to read its record {file}, so the account the worker runs as cannot answer it{answer} (cause {lower})give the account the worker runs as read access to {file} (`ls -l {file}` shows its owner and mode)config, exit 1, HTTP 500tests/admission/records/record-failures.mjs::status_refuses_a_task_record_the_worker_cannot_read
task-record-foreignreading public task {task_id}its record {file} is not task {task_id} of this organization: {answer}; it was edited or written by another deployment sharing this home{file}: {answer}restore {file} from the worker host backup, or move it to the deployment it belongs to so the task reads as not found hereconfig, exit 1, HTTP 500tests/admission/records/record-failures.mjs::status_refuses_a_task_record_of_another_organization
cancellation-schema-unsupportedreading the cancellationthe body is not an object whose schema is {expected}schema: {schema}send a cancellation object with "schema": "{expected}"refused, exit 1, HTTP 400tests/admission/records/record-failures.mjs::cancel_refuses_a_cancellation_of_another_schema
cancellation-fields-undeclaredreading the cancellationits fields are not exactly the ones {schema} declares{reasons}send exactly the fields {declared}refused, exit 1, HTTP 400tests/admission/records/record-failures.mjs::cancel_refuses_a_cancellation_with_undeclared_fields
cancellation-reason-emptyreading the cancellationreason is not a non-empty string, and every cancellation records whyreason: {value}send one sentence saying who cancels the task and whyrefused, exit 1, HTTP 400tests/admission/records/record-failures.mjs::cancel_refuses_a_cancellation_without_a_reason
cancellation-conflictcancelling public task {task_id}the task already has a cancellation under another Idempotency-Key or reason, and one task is cancelled oncerecorded cancellation: key {recorded_key}, reason {recorded_reason}read the task with GET /api/v1/tasks/{task_id}; to retry the recorded cancellation, resend it with its key and reasonrefused, exit 1, HTTP 409tests/admission/records/record-failures.mjs::cancel_refuses_a_second_cancellation_with_another_reason
published-missingreading the Stado-published document {path}the file cannot be examined ({code}): Stado has not published it on this host, or the setting {setting} names another path{path}: {answer}republish it with Stado: `stado service directory publish --service weles-admission` writes the directory and transport; the placement policy is the one the fleet publishes for this host, which WELES_PLACEMENT_POLICY_FILE names, or set {setting} to where it is publishedconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_without_a_published_policy_names_the_file
published-linkreading the Stado-published document {path}it is a symbolic link, and Stado writes it as a regular file: a link could point at a document Stado never published{path} is a symbolic linkrepublish it with Stado: `stado service directory publish --service weles-admission` writes the directory and transport; the placement policy is the one the fleet publishes for this host, which WELES_PLACEMENT_POLICY_FILE namesconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_a_linked_policy_names_the_link
published-not-filereading the Stado-published document {path}it is not a regular file (a directory or a device){path}: {kind}move {path} aside and republish it with Stado: `stado service directory publish --service weles-admission` writes the directory and transport; the placement policy is the one the fleet publishes for this host, which WELES_PLACEMENT_POLICY_FILE namesconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_a_directory_for_a_policy_names_it
published-emptyreading the Stado-published document {path}the file is empty: the publish that wrote it was cut off{path}: 0 bytesrepublish it with Stado: `stado service directory publish --service weles-admission` writes the directory and transport; the placement policy is the one the fleet publishes for this host, which WELES_PLACEMENT_POLICY_FILE namesconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_an_empty_policy_names_it
published-not-jsonreading the Stado-published document {path}it is not one JSON document: the publish that wrote it was cut off or another program wrote it{path} ({bytes} bytes) begins {head}; parser: {answer}republish it with Stado: `stado service directory publish --service weles-admission` writes the directory and transport; the placement policy is the one the fleet publishes for this host, which WELES_PLACEMENT_POLICY_FILE namesconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_a_policy_that_is_not_json_names_it
placement-identityreading the placement policy {path}its {field} is {found}, where a placement policy the fleet publishes for this host holds {expected}{path}: {field} {found}republish it with Stado: `stado service directory publish --service weles-admission` writes the directory and transport; the placement policy is the one the fleet publishes for this host, which WELES_PLACEMENT_POLICY_FILE namesconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_a_policy_of_another_publisher_names_the_field
placement-hostsfinding the host the placement policy {path} authorizes for generic_browser_task{count} enabled host(s) carry generic_browser_task, where exactly one is the public servicehosts carrying it: {hosts}enable generic_browser_task on exactly one host in the fleet's placement policy, and point WELES_PLACEMENT_POLICY_FILE at the policy published for this hostconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_two_public_hosts_names_both
directory-identityreading the service-directory snapshot {path}its {field} is {found}, where this worker expects {expected}: the directory names another host, release or service than the one running here{path}: {field} {found}move this host onto the release the directory names (`stado service update weles-admission`), or republish the directory once this release is active (`stado service directory publish --service weles-admission`)config, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_a_directory_of_another_release_names_the_field
directory-endpoint-invalidreading service.endpoint of the service-directory snapshot {path}the endpoint {why}; it is the exact absolute /api/v1 base URL of the public task APIservice.endpoint: {found}republish it with Stado: `stado service directory publish --service weles-admission` writes the directory and transport; the placement policy is the one the fleet publishes for this host, which WELES_PLACEMENT_POLICY_FILE namesconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_a_directory_endpoint_of_another_path_names_it
transport-differscomparing the local admission transport {path} with the published endpointthe transport {why}, so callers reaching the published endpoint would not reach this workertransport: {found}; published endpoint: {expected}republish it with Stado: `stado service directory publish --service weles-admission` writes the directory and transport; the placement policy is the one the fleet publishes for this host, which WELES_PLACEMENT_POLICY_FILE namesconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_with_a_transport_elsewhere_names_both_addresses
deployed-identity-mismatchvalidating the deployed service identity against this releaseits {field} is {found}, where the immutable release expects {expected}{field}: {found}move this host onto the release the directory names (`stado service update weles-admission`), or republish the directory for this releaseconfig, exit 1, HTTP 503tests/admission/identities/identity-failures.mjs::version_of_an_identity_for_another_release_names_the_field
state-entry-unexpectedrecovering the public tasks under {root}unexpected public task state entry: {entry}: the task directory holds only task-<uuid>.json files and the idempotency directory, and this is neither{entry} under {root} ({kind})move the file named aside (the worker never removes what it did not write), then `weles worker restart`; GET /worker/status names the recovery failureconfig, exit 1, HTTP 500tests/worker/failures.mjs::worker_restart_over_task_state_that_is_no_task_names_the_entry
reservation-entry-unexpectedrecovering the Idempotency-Key reservations under {root}unexpected public task reservation entry: {entry}: the idempotency directory holds only reservation files, and this is none{entry} under {root} ({kind})move the file named aside (the worker never removes what it did not write), then `weles worker restart`; GET /worker/status names the recovery failureconfig, exit 1, HTTP 500tests/admission/records/state-failures.mjs::recovery_over_a_stray_reservation_entry_names_it
reservation-invalidreading the Idempotency-Key reservation {path}its {field} is {found} where a reservation of this organization holds {expected}: it was edited, truncated or written by another deployment{path}: {field} {found}move the file named aside (the worker never removes what it did not write), then `weles worker restart`; GET /worker/status names the recovery failureconfig, exit 1, HTTP 500tests/admission/records/state-failures.mjs::recovery_over_a_reservation_of_another_shape_names_the_field
reservation-task-unmatchedreading public task {task} its reservation namesthe task file under {root} is not the task its reservation names: {problem}reservation digest {reserved}; task digest {recorded}move the file named aside (the worker never removes what it did not write), then `weles worker restart`; GET /worker/status names the recovery failureconfig, exit 1, HTTP 500tests/admission/records/state-failures.mjs::recovery_of_a_task_other_than_its_reservation_names_it
reservation-unclosedwriting the Idempotency-Key reservation {path}the write failed ({answer}) and its open file handle could not be closed either ({close}); the reservation was removed so the key can be sent again{path}: write {answer}; close {close}free space on the disk of {root} and check its file system (`df -h {root}`), then send the task again with the same Idempotency-Keyinfra_down, exit 69, HTTP 500, retryabletests/admission/records/state-failures.mjs::a_reservation_whose_handle_cannot_close_is_named
reservation-vanishedreading the Idempotency-Key reservation another request createdthe reservation another request created for this key disappeared under {root} before it could be read: something other than this worker removed itno reservation for the key under {root}find what removes files under {root} (a cleanup job, another worker sharing the home), then send the task againconfig, exit 1, HTTP 500tests/admission/records/state-failures.mjs::a_reservation_removed_between_two_requests_is_named
state-write-unpublishedwriting {path} atomicallythe {kind} write did not publish {path} ({answer}), and its temporary file {temporary} could not be removed either ({cleanup}){path}: {answer}; {temporary}: {cleanup}free space on that disk and give the worker user write access to its directory, remove {temporary} by hand, then `weles worker restart`infra_down, exit 69, HTTP 500, retryabletests/admission/records/state-failures.mjs::an_atomic_write_whose_temporary_file_stays_is_named
state-write-refusedwriting {path} atomicallythe system refused to {step} {target} ({errno}): the {kind} write creates the directory, writes and syncs a temporary file, renames it over {path} and syncs the directory, in that order, and {path} is unchanged{target}: {errno}; system: {answer}free space on that disk and give the account the worker runs as write access to {target}, then `weles worker restart`; GET /worker/status names the write recovery metinfra_down, exit 69, HTTP 500, retryabletests/admission/records/state-failures.mjs::a_write_into_a_directory_the_worker_cannot_write_is_named
state-read-refusedreading the public task state file {path}the system refused to {step} it ({errno}), so the task or reservation it holds cannot be answered or recovered{path}: {errno}; system: {answer}give the account the worker runs as read access to {path} (`ls -l {path}` shows its owner and mode), then `weles worker restart`infra_down, exit 69, HTTP 500, retryabletests/admission/records/state-failures.mjs::a_task_file_the_worker_cannot_read_is_named
task-status-unwiredanswering the status of public task {task}its status {status} is outside the wire vocabulary Spis reads ({statuses}), so it is not answered mid-crawl as one Spis cannot readtask {task}: status {status}compare `weles worker version` with the release that wrote the task; a task of another release is read by that releaseconfig, exit 1, HTTP 500tests/admission/records/state-failures.mjs::a_task_of_a_status_outside_the_wire_is_named
task-receipt-missinganswering the terminal status of public task {task}the task ended ({status}) without the retained-evidence receipt every terminal answer carriestask {task}: status {status}, no receiptGET /worker/status names the retention failure of the task; retain its evidence again once the object store answersconfig, exit 1, HTTP 500tests/admission/records/state-failures.mjs::a_terminal_task_without_its_receipt_is_named
canonical-json-uncarriedwriting {path} as canonical JSONcanonical JSON cannot carry {what}, and the value was built by Weles, not admitted from a request: a defect of this release{path}: {what}report it with `weles worker version` and the request that built the value; nothing was signed or answered with itunknown, exit 1, HTTP 500tests/admission/records/state-failures.mjs::canonical_json_of_a_value_it_cannot_carry_is_named
state-file-not-jsonreading the public task state file {path}it is not one JSON document: the worker writes it whole and renames it into place, so it was truncated or written by something else{path} ({bytes} bytes) begins {head}; parser: {answer}move the file named aside (the worker never removes what it did not write), then `weles worker restart`; GET /worker/status names the recovery failureconfig, exit 1, HTTP 500tests/admission/records/state-failures.mjs::recovery_over_a_task_file_that_is_not_json_names_it
evidence-root-unsafehashing task {task}'s evidence under {root}the run directory is {kind}, not a directory of its own: a receipt is signed only over files the run wrote under it{root} is {kind}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_run_directory_that_is_a_link_is_quarantined
evidence-path-unsafehashing task {task}'s evidence under {root}evidence path component is not portable: the entry {name} holds a character outside A-Z, a-z, 0-9, dot, underscore and hyphen, which a locator cannot carry unchanged{name} in {directory}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::an_entry_whose_name_is_not_portable_is_quarantined
evidence-symlinkhashing task {task}'s evidence under {root}symlink is forbidden in evidence: {name} points outside the bytes the run wrote, so hashing it would sign whatever it points at{name} in {directory} is a symbolic link to {target}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_link_inside_the_run_directory_is_quarantined
evidence-entry-unsafehashing task {task}'s evidence under {root}non-regular evidence entry is forbidden: {path} is {kind}, which holds no bytes a receipt could name{path} under {root} is {kind}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_socket_inside_the_run_directory_is_quarantined
evidence-file-unsafehashing task {task}'s evidence under {root}evidence path is not a regular file: {path} was listed as a file but is {kind} when opened, so something replaced it while the run directory was read{path} is {kind}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_file_replaced_while_listed_is_quarantined
evidence-file-unstablehashing task {task}'s evidence under {root}evidence file changed while hashing: {path} has another size, inode or time after its bytes were read, so the digest names no one version of it{path}: {before} before hashing, {after} afternothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_file_written_while_hashed_is_quarantined
evidence-file-emptyhashing task {task}'s evidence under {root}retained evidence file is empty: {path} holds 0 bytes, and the Spis bridge refuses an inventory entry of no bytes, so the receipt could never be verified{path} under {root}: 0 bytesnothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::an_empty_evidence_file_is_quarantined
withheld-edge-not-jsonhashing task {task}'s evidence under {root}withheld-edge evidence is not valid NDJSON: record {record} of {path} is not a JSON document, so the withheld edges the receipt counts cannot be read{path} record {record} begins {head}; parser: {answer}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_withheld_edge_that_is_not_json_is_quarantined
withheld-edge-not-objecthashing task {task}'s evidence under {root}withheld-edge evidence is not valid NDJSON: record {record} of {path} is {kind}, not one object per edge{path} record {record}: {head}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_withheld_edge_that_is_no_object_is_quarantined
required-evidence-missinghashing task {task}'s evidence under {root}successful browser-evidence task lacks {missing}: a succeeded task is signed only over its final screenshot (artifacts/browser_evidence_final.png) and accessibility tree (artifacts/browser_evidence_accessibility_tree.txt){root} holds {count} file(s): {files}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_succeeded_task_without_its_screenshot_is_quarantined
policy-evidence-missinghashing task {task}'s evidence under {root}successful browser-evidence task has no retained policy document: no browser_evidence_policy.json is under the run directory, so the receipt could not say which policy the capture obeyed{root} holds {count} file(s): {files}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_succeeded_task_without_its_policy_is_quarantined
evidence-identity-duplicatehashing task {task}'s evidence under {root}evidence inventory kind and URI identities must be unique, and {duplicates} repeat: each is derived from a distinct relative path, so this is a defect of this release{count} inventory entries, {kinds} distinct kinds, {uris} distinct URIsreport it with `weles worker version` and the task id; the task settled as failed and its evidence is kept asideunknown, exit 1, HTTP 500tests/admission/retention-failures.mjs::an_inventory_with_a_repeated_identity_is_quarantined
evidence-manifest-unsaferetaining task {task}'s evidence manifest {manifest}existing evidence manifest is not a regular file: {manifest} is {kind}, and only a manifest this worker wrote can be compared with the one it computes{manifest} is {kind}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_manifest_that_is_a_directory_is_quarantined
evidence-manifest-conflictretaining task {task}'s evidence manifest {manifest}existing evidence manifest disagrees with recomputed immutable task identity: a manifest once written is never rewritten, and the one on disk is not the one this task computes{manifest}: {found} bytes on disk, {expected} bytes computed (sha256 {digest})nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::a_manifest_of_another_task_is_quarantined
evidence-changedretaining task {task}'s evidence manifest {manifest}evidence changed between hashing and durable retention: the run directory read again after the upload holds another inventory, so storage may hold bytes the manifest does not namehashed {before}; after the upload {after}nothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::evidence_changed_during_the_upload_is_quarantined
withheld-edge-changedretaining task {task}'s evidence manifest {manifest}withheld-edge evidence changed before receipt signing: the edges read after the readback are not the ones counted before the upload{before} edge(s) before the upload, {after} afternothing to do for this task: it settled as failed with this code, its evidence is kept aside under {root}/../.public-task-retention-failures; fix what wrote the entry into the run directory, so the next run does not meet itconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::withheld_edges_changed_before_signing_are_quarantined
evidence-unreadablehashing task {task}'s evidence under {root}the system refused to {step} {path}, so the inventory cannot be hashed; the evidence is left where it is{path}: {errno}; system: {answer}make {path} readable by the account the worker runs as; the task stays pending and is retried on its next read (`weles tasks show {task}`), sweep or `weles worker restart`; `weles doctor` shows whether the Stado object API answersconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::an_unreadable_evidence_directory_leaves_the_task_pending
evidence-quarantine-unmovedmoving task {task}'s evidence aside after {code}the system refused to {step} {path}: create the quarantine directory, move the run directory into it, sync, create artifacts/ and write the diagnostic run in that order, and the steps before this one were done{path}: {errno}; system: {answer}free or make writable the file system holding {path}, then `weles worker restart`: recovery retains the task again; the read or recovery that met this answered it, and the task file was not changedconfig, exit 1, HTTP 500tests/admission/retention-failures.mjs::evidence_that_cannot_be_moved_aside_is_named
manifest-unacknowledgedretaining task {task}'s evidence manifest {manifest}durable artifact storage did not acknowledge the exact evidence manifest: the upload answered locators, but none of them is {manifest}locators answered: {locators}the task stays pending and is retried on its next read (`weles tasks show {task}`), sweep or `weles worker restart`; `weles doctor` shows whether the Stado object API answersinfra_down, exit 69, HTTP 502, retryabletests/admission/retention-failures.mjs::an_upload_that_omits_the_manifest_leaves_the_task_pending
manifest-readback-differsretaining task {task}'s evidence manifest {manifest}durable evidence manifest readback differs from the retained canonical bytes: storage answers another object at {manifest}read back {bytes} bytes, sha256 {sha256}; written {expected_bytes} bytes, sha256 {expected_sha256}the task stays pending and is retried on its next read (`weles tasks show {task}`), sweep or `weles worker restart`; `weles doctor` shows whether the Stado object API answersinfra_down, exit 69, HTTP 502, retryabletests/admission/retention-failures.mjs::a_manifest_read_back_otherwise_leaves_the_task_pending
evidence-readback-differsretaining task {task}'s evidence manifest {manifest}durable evidence readback differs from inventory: {kind}: storage answers another object at {uri}read back {bytes} bytes, sha256 {sha256}; inventory {expected_bytes} bytes, sha256 {expected_sha256}the task stays pending and is retried on its next read (`weles tasks show {task}`), sweep or `weles worker restart`; `weles doctor` shows whether the Stado object API answersinfra_down, exit 69, HTTP 502, retryabletests/admission/retention-failures.mjs::an_evidence_file_read_back_otherwise_leaves_the_task_pending

tasks#

5 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
document-unreadablereading {what} from {path}the file cannot be read: it does not exist, it is a directory, or this user may not read it{answer}name a file this user can read, or - for standard inputconfig, exit 1, HTTP 503tests/tasks/failures.mjs::a_request_file_that_cannot_be_read_is_named
document-not-objectreading {what} from {path}the file does not hold one JSON object: it is not JSON, or JSON of another shape{answer}write {what} as one JSON objectrefused, exit 1, HTTP 403tests/tasks/failures.mjs::a_request_that_is_not_a_json_object_is_refused
route-unnamedfinding the public task API for `weles tasks {verb}`the command names neither --consumer (whose route Stado places) nor --endpoint, or names both--consumer: {consumer}; --endpoint: {endpoint}name exactly one: --consumer <the Stado consumer you call as> or --endpoint <the API address>refused, exit 2, HTTP 403tests/tasks/failures.mjs::a_task_command_naming_no_route_is_refused
route-unresolvedfinding the public task API for consumer {consumer}Stado places no weles-admission service consumer {consumer} can connect to from here{answer}run where `stado service directory connect weles-admission --consumer {consumer}` answers a url, or name the address with --endpointnot_found, exit 1, HTTP 404tests/tasks/failures.mjs::a_consumer_stado_places_no_api_for_is_named
task-id-invalidreading the task id of `weles tasks {verb}`a public task id is the lower-case UUID `weles tasks submit` answered as taskId, and this is not onetask id: {id}name the taskId the submission answeredrefused, exit 2, HTTP 403tests/tasks/failures.mjs::a_task_id_that_is_no_uuid_is_refused

receipts#

10 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
keys-invalidreading the receipt keys {path}a key map is one JSON object of key id to PEM public key, with at least one key; this one is empty or holds a key that is not text{answer}write the published receipt key set as {"<key id>": "-----BEGIN PUBLIC KEY-----..."}refused, exit 1, HTTP 403tests/tasks/receipt-failures.mjs::a_key_map_without_keys_is_refused
receipt-malformedverifying the receipt {receipt}a receipt is one object with schema, keyId, signature and signedPayload as text, and this one lacks one of them{answer}pass the receipt object a terminal task answered, whole and unchangedrefused, exit 1, HTTP 403tests/tasks/receipt-failures.mjs::a_receipt_lacking_its_signature_is_refused
receipt-schema-unsupportedverifying the receipt {receipt}the receipt names a schema this Weles does not verify (weles.receipt.current): another product wrote it, or a newer Welesschema: {schema}verify it with the Weles release that signed it (`weles version` names this one)refused, exit 1, HTTP 403tests/tasks/receipt-failures.mjs::a_receipt_of_another_schema_is_refused
receipt-key-unknownverifying the receipt {receipt}the key map holds no public key under the id the receipt was signed with: the key set was rotated after it was copied, or it is another deployment'skeyId: {key}; the map holds: {keys}read the published receipt key set again (the role's receipt_public_keys_json) and pass it with --keysrefused, exit 1, HTTP 403tests/tasks/receipt-failures.mjs::a_receipt_signed_with_a_key_the_map_lacks_is_refused
receipt-key-unusableverifying the receipt {receipt}the public key the map holds under the receipt's key id is not a PEM public key the verifier can usekeyId: {key}: {answer}pass the published PEM public key under that id, unchangedconfig, exit 1, HTTP 503tests/tasks/receipt-failures.mjs::a_key_that_is_not_a_public_key_is_named
receipt-signature-invalidverifying the receipt {receipt}the signature does not verify against the signed payload with that key: the receipt was altered, or signed by another key under the same idkeyId: {key}do not trust this receipt; read the task again (`weles tasks show <task-id>`) for the receipt Weles signedrefused, exit 1, HTTP 403tests/tasks/receipt-failures.mjs::an_altered_receipt_is_refused
receipt-payload-not-jsonverifying the receipt {receipt}the signature verifies and the signed payload is not one JSON object, so the receipt states no claims{answer}report the receipt with `weles version`: a Weles that signs such a payload has a defectrefused, exit 1, HTTP 403tests/tasks/receipt-failures.mjs::a_receipt_whose_signed_payload_is_no_object_is_refused
receipt-claim-mismatchverifying the receipt {receipt}a field the receipt displays differs from the claim its signed payload carries, so what it shows is not what was signedfield: {field}trust only the signed claims; read the task again (`weles tasks show <task-id>`) for the receipt Weles signedrefused, exit 1, HTTP 403tests/tasks/receipt-failures.mjs::a_receipt_displaying_another_outcome_is_refused
receipt-refused-otherverifying the receipt {receipt}the verifier (weles-client) refused the receipt with {code}, a refusal this release does not knowit said: {answer}install the Weles release made for the weles-client it carries (`stado product install weles --surface cli`)unknown, exit 1, HTTP 500tests/tasks/receipt-failures.mjs::a_refusal_of_a_newer_verifier_is_named
receipt-claim-missingverifying the receipt {receipt}the receipt verifies and its signed claims carry no non-empty {field}, which the first-use journey recordsthe claims hold {members}report the receipt with `weles version`: a Weles signs every claim the journey recordsrefused, exit 1, HTTP 403tests/onboarding/stages/steps-failures.mjs::signed_claims_without_an_evidence_digest_are_refused

Browser#

How a session driven through weles mcp fails. The JSON-RPC error message is the sentence; error.data carries the cause, remedy and docs. A failure the browser engine reports is classified by the engine's own words and quoted whole.

55 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
release-family-unknownfinding the selected release of browser family "{engine}"Weles launches only a released chromium or firefox, and "{engine}" is neitherbrowser family "{engine}"; released families: {families}name the browser as chromium or firefoxrefused, exit 2, HTTP 403tests/browser/launching/release-failures.mjs::a_browser_family_weles_does_not_release_is_refused
release-platform-unsupportedfinding the selected weles-{engine} releaseweles-{engine} releases are published for darwin-arm64, darwin-amd64 and linux-amd64 only, and this host is {platform}process.platform {os}, process.arch {arch}run the browser on a darwin-arm64, darwin-amd64 or linux-amd64 hostconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_host_of_another_platform_is_refused
release-root-unnamedfinding the selected weles-{engine} release{variable} is unset and HOME is unset or empty, so there is no install root to look in (it is {variable}, else $HOME/.local/share/weles-{engine}){variable} unset; HOME "{home}"set {variable} to the directory weles-{engine} is installed in, or run with HOME setconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_host_without_home_or_install_root_is_refused
release-pin-partialfinding the selected weles-{engine} releasethe deployment pins a release only with both {versionVariable} and {digestVariable}, and only {given} is set{given} set; {missing} unsetset {missing} too, or unset {given} so the release {root}/selected records is usedconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_pin_with_only_its_version_is_refused
release-unselectedfinding the selected weles-{engine} releaseno weles-{engine} release is selected: neither {versionVariable} and {digestVariable} are set nor does {record} exist{record} absent; {variable} {rootSource}install weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selected, or pin it with {versionVariable} and {digestVariable}config, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_host_without_the_browser_release_names_where_it_looked
release-selection-unreadablereading the selection record {record}the selection record {record} exists and cannot be read as a file{code}: {problem}make {record} a file this user may read; install weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selectedconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_selection_record_that_is_a_directory_is_named
release-selection-incompletereading the selection record {record}the selection record {record} names no {missing}, and a release is used only by its version and its sha256 together{record} reads {fields}install weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selected; it writes version=<version> and sha256=<archive digest>config, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_selection_without_its_digest_is_named
release-digest-invalidfinding the selected weles-{engine} releasethe selected weles-{engine} {version} release names a checksum that is not 64 hex digits of a SHA-256, so no receipt can be checked against itsha256 "{digest}" ({length} characters) from {source}give the archive SHA-256 the weles-{engine} {version} release was published with, in {source}config, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_selection_whose_digest_is_no_sha256_is_named
release-executable-absentfinding the selected weles-{engine} releasethe selected weles-{engine} {version} release has no executable at {binary}: that version is not installed under {root}, or is installed for another platform layout{binary} absent; {installDir} {installState}install weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selectedconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_selected_release_without_its_executable_is_named
release-executable-unexaminableexamining the executable {binary}the executable of the selected release cannot be examined: a directory on its path may not be searched by this user{code}: {problem}let this user search every directory on the path of {binary}, or install weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selected into a directory it mayconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::an_executable_behind_a_closed_directory_is_named
release-executable-not-filefinding the selected weles-{engine} release{binary} is a {kind}, not the executable file the release installs{binary}: {kind}remove {binary} and install weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selectedconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::an_executable_that_is_a_directory_is_named
release-receipt-absentreading the receipt of weles-{engine} {version}the install at {installDir} has no receipt {receipt}, which the install writes only after it verified the archive, so its executable is not used{receipt} absent; {binary} presentinstall weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selectedconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_release_without_its_receipt_is_named
release-receipt-unreadablereading the receipt {receipt}the receipt {receipt} exists and cannot be read as a file{code}: {problem}make {receipt} a file this user may read; install weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selectedconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_receipt_that_is_a_directory_is_named
release-receipt-mismatchchecking the receipt {receipt} against the selected releasethe receipt records another release than the one selected: the install under {installDir} is of another version, platform or archive digestexpected {expected}; found {found}install weles-{engine} with that release's release/install.sh, which verifies the archive, writes {root}/{version}/.weles-release and records the release in {root}/selectedconfig, exit 1, HTTP 503tests/browser/launching/release-failures.mjs::a_receipt_of_another_release_is_named
browser-engine-unknownstarting a browserbrowser names no engine Weles launchesbrowser: {value}give browser as chromium or firefoxrefused, exit 2, HTTP 403tests/browser/launching/launch-failures.mjs::an_unknown_engine_is_refused_before_launch
browser-os-unknownstarting a browseros names no operating system a Weles persona presentsos: {value}give os as macos, windows or linuxrefused, exit 2, HTTP 403tests/browser/launching/launch-failures.mjs::an_unknown_os_is_refused_before_launch
browser-window-unsizedstarting a browserthe launch states no window size: WELES_VIEWPORT is unset, no persona was given, and the host screen is not readWeles said: {answer}set WELES_VIEWPORT=<width>x<height> in the environment of weles mcp (1280x800, say), or turn the honest host on so Weles reads the screenconfig, exit 1, HTTP 503tests/browser/launching/launch-failures.mjs::a_launch_without_a_window_size_names_the_variable
browser-launch-refusedstarting a browserWeles refused the launch before starting the engine: a setting the launch needs is missing or contradicts another, in Weles' own words belowWeles said: {answer}set what the sentence names in the environment of weles mcp, then start the browser againconfig, exit 1, HTTP 503tests/browser/launching/launch-failures.mjs::a_launch_weles_refuses_quotes_its_reason
browser-profile-unusableopening the browser profile {profile}userDataDir cannot hold a profile: a file stands at that path, its parent is not a directory, or the server user may not write thereWeles said: {answer}give userDataDir as a directory this server can create and write, or leave it out for a fresh profileconfig, exit 1, HTTP 503tests/browser/launching/launch-failures.mjs::a_profile_path_that_is_a_file_is_named
browser-launch-failedlaunching {engine}the browser executable started but exited or never opened its control channel: a damaged install, a missing system library, or a sandbox that refuses itthe engine said: {answer}run the executable the message names by hand to see why it exits, then reinstall the selected weles-{engine} release through Stadoconfig, exit 1, HTTP 503tests/browser/launching/launch-failures.mjs::a_browser_that_exits_at_launch_is_named_with_the_engine_words
recording-encoder-missing{tool} in a recorded browserthe session records video and the ffmpeg encoder Playwright records with is not installed where PLAYWRIGHT_BROWSERS_PATH pointsthe engine said: {answer}install it with `npx playwright install ffmpeg` (the release ships it under browser-runtime), or start weles mcp with WELES_DISABLE_RECORDING=1config, exit 1, HTTP 503tests/browser/launching/launch-failures.mjs::a_recorded_session_without_ffmpeg_names_the_encoder
not-placed-here{entrypoint} starting a browser on this hostthe Stado registry places the Weles service on other hosts, and a browser started off its placement runs where nobody routes work{entrypoint} is not placed on registry target '{target}'; Weles is placed on {placed}run it where `stado service status com.wisent.weles --json` places Weles, or set WELES_STANDALONE=1 on a machine that runs Weles without Stadorefused, exit 1, HTTP 403tests/keeper/control/control-failures.mjs::a_browser_off_its_placement_is_refused
navigation-url-invalidopening {url}the engine cannot navigate to it: it is not an absolute URL with a scheme the browser opensthe engine said: {answer}give url as an absolute address such as https://example.com/refused, exit 2, HTTP 403tests/browser/navigation-failures.mjs::a_url_the_browser_cannot_open_is_refused
navigation-host-unresolvedopening {url}the host has no DNS answer: it does not exist, or this machine reaches no resolver (or the proxy the browser uses cannot resolve it)the engine said: {answer}check the host name; if it resolves elsewhere, check this machine's DNS or the proxy given to weles_browser_startnot_found, exit 1, HTTP 404tests/browser/navigation-failures.mjs::a_host_without_dns_is_named
navigation-connection-refusedopening {url}nothing accepts connections at that address and port: the site is down, or a firewall rejects the browserthe engine said: {answer}start the service at that address or correct the port, then call againinfra_down, exit 69, HTTP 503, retryabletests/browser/navigation-failures.mjs::a_closed_port_is_named
navigation-certificate-refusedopening {url}the browser refused the site's TLS certificate: it is self-signed, expired, issued for another host, or signed by an authority the browser does not trustthe engine said: {answer}serve the site with a certificate a public authority issued for its host; Weles does not open a page whose certificate it cannot verifyrefused, exit 1, HTTP 403tests/browser/navigation-failures.mjs::a_self_signed_certificate_is_named
navigation-network-failedopening {url}the connection was made but broke before a response: the server closed it, reset it or sent no HTTP answerthe engine said: {answer}check the server at that address answers HTTP (curl -v the URL), then call againinfra_down, exit 69, HTTP 503, retryabletests/browser/navigation-failures.mjs::a_server_that_closes_the_connection_is_named
page-request-failedsending {method} {url} from page {page}the request got no HTTP answer: the host has no DNS answer, nothing listens there, or the connection brokethe engine said: {answer}check the address answers (curl -v the URL), then call againinfra_down, exit 69, HTTP 503, retryabletests/browser/navigation-failures.mjs::an_in_page_request_to_a_closed_port_is_named
storage-file-unreadablereading the storage state {path}the file cannot be read: it does not exist, or the server user may not read it{answer}give path as a storage-state file this server can read, such as one context.storageState({ path }) wrotenot_found, exit 1, HTTP 404tests/browser/page-failures.mjs::a_storage_file_that_does_not_exist_is_named
storage-file-not-statereading the storage state {path}the file is not a Playwright storage state: it is not JSON, or it lacks the cookies and origins arrays{answer}give a file of the form { "cookies": [...], "origins": [...] }, as context.storageState() writes itrefused, exit 1, HTTP 403tests/browser/page-failures.mjs::a_storage_file_that_is_not_a_state_is_named
selector-invalid{tool} on page {page}the selector is not one the engine parsesthe engine said: {answer}give a Playwright selector: CSS, role=button[name="Start"], text=Continue or internal:label="Email"refused, exit 2, HTTP 403tests/browser/page-failures.mjs::a_selector_the_engine_cannot_parse_is_named
page-script-threw{tool} on page {page}the expression threw inside the pagethe page said: {answer}correct the expression; run it in the page console to see the same errorrefused, exit 1, HTTP 403tests/browser/page-failures.mjs::an_expression_that_throws_is_answered_with_the_page_error
browser-closed{tool} on page {page}the page or its browser is gone: it was closed, or the browser process exited or crashedthe engine said: {answer}open the browser and page again with weles_browser_start and weles_page_newnot_found, exit 1, HTTP 404tests/browser/page-failures.mjs::a_page_whose_browser_closed_is_named
upload-file-missing{tool} on page {page}a file to upload does not exist or cannot be read by the server userthe engine said: {answer}give files as absolute paths of readable files on the machine weles mcp runs onnot_found, exit 1, HTTP 404tests/browser/page-failures.mjs::an_upload_of_a_missing_file_is_named
engine-refused{tool} on page {page}the browser engine refused the operation for a reason Weles does not classify further, stated in its own words belowthe engine said: {answer}read the engine's words: they name the element, state or value it refused; correct that argument and call againrefused, exit 1, HTTP 403tests/browser/page-failures.mjs::an_engine_refusal_is_quoted_whole
secret-field-missingreading the secret weles_page_fill_secret fillsSkarbiec item {item} holds no text in field {field}; it holds {fields}the fields it holds: {fields}name a field the item holds, or store the secret in field {field}not_found, exit 1, HTTP 404tests/browser/page-failures.mjs::a_secret_fill_from_a_field_the_item_lacks_names_its_fields
audit-unavailableauditing the accessibility of page {page}axe-core could not be put in the page: {reason}the auditor this release carries, {path}; no audit was performed and nothing is reported as passinginstall a Weles release whose vendor/axe-core/axe.min.js is present and readable, or open a page whose policy lets an injected script runnot_found, exit 1, HTTP 404tests/browser/page-failures.mjs::an_audit_without_its_auditor_names_the_file
request-not-jsonreading one request linethe line is not a JSON document, so it names no method and no id to answerthe parser said: {answer}write one JSON-RPC 2.0 request per line, such as {"jsonrpc":"2.0","id":1,"method":"tools/list"}refused, exit 2, HTTP 403tests/browser/protocol-failures.mjs::a_line_that_is_not_json_is_answered_with_the_parser_reason
method-unknownanswering method {method}weles mcp answers only initialize, ping, tools/list and tools/callmethod: {method}send one of initialize, ping, tools/list or tools/callrefused, exit 2, HTTP 403tests/browser/protocol-failures.mjs::an_unknown_method_names_the_methods_served
call-without-paramscalling a tooltools/call carries no params, so it names no toolparams: nonesend params { "name": "<tool>", "arguments": { ... } }; tools/list names every toolrefused, exit 2, HTTP 403tests/browser/protocol-failures.mjs::a_tool_call_without_params_names_what_it_needs
tool-unknowncalling tool {tool}weles mcp serves no tool of that nametools served: {tools}call one of the tools tools/list answersrefused, exit 2, HTTP 403tests/browser/protocol-failures.mjs::an_unknown_tool_names_the_tools_served
argument-missingreading argument {name} of {tool}{name} is required and was not given, or was given empty{name}: {value}give {name} as its schema in tools/list statesrefused, exit 2, HTTP 403tests/browser/protocol-failures.mjs::a_missing_argument_is_named
argument-typereading argument {name} of {tool}{name} must be {expected}{name}: {value}give {name} as {expected}refused, exit 2, HTTP 403tests/browser/protocol-failures.mjs::an_argument_of_the_wrong_type_is_named
browser-id-unknownfinding browser {id}this server never handed out that browserId, or the browser was closed, or the server restarted sincebrowsers open in this server: {open}start a browser with weles_browser_start and use the browserId it answersnot_found, exit 1, HTTP 404tests/browser/protocol-failures.mjs::an_unknown_browser_id_lists_the_open_ones
page-id-unknownfinding page {id}this server never handed out that pageId, or its browser was closed, or the server restarted sincepages open in this server: {open}open a page with weles_page_new and use the pageId it answersnot_found, exit 1, HTTP 404tests/browser/protocol-failures.mjs::an_unknown_page_id_lists_the_open_ones
open-url-missingreading the weles open command lineweles open needs the <url> of the page to openpositional arguments: {given}run `weles open <url> --os macos|windows|linux --browser chromium|firefox`refused, exit 2, HTTP 403tests/browser/launching/open-failures.mjs::open_without_a_url_names_what_it_takes
open-locale-invalidreading --locale of weles open--locale is not a BCP 47 language tag--locale: {value}; {answer}give --locale a tag such as pl-PL or derefused, exit 2, HTTP 403tests/browser/launching/open-failures.mjs::open_with_a_locale_that_is_no_language_tag_is_refused
open-close-failedclosing the browser weles open launchedthe page was read, and closing its browser failed in the engine words below, so its recording may be unfinishedthe engine said: {answer}read the engine words; a browser process left running is ended with `pkill -f <its profile>`config, exit 1, HTTP 503tests/browser/launching/open-failures.mjs::open_whose_browser_cannot_close_names_it
observed-target-ambiguousresolving the observed control {target} on {url}[observed_target_ambiguous] Multiple controls share this description; include the observed index: {count} control(s) in {where} are described alike{target}: {count} matching controls in {where}observe the page again and name the control by the description, with its [n] index, the new observation printsrefused, exit 2, HTTP 403tests/browser/controls-failures.mjs::a_description_two_controls_share_is_refused
observed-target-invalidresolving the observed control {target} on {url}[observed_target_invalid] Invalid control index: {index} is beyond the integers a page can numberindex {index} in {target}observe the page again and name the control by the description, with its [n] index, the new observation printsrefused, exit 2, HTTP 403tests/browser/controls-failures.mjs::an_index_no_page_numbers_is_refused
observed-target-staleresolving the observed control {target} on {url}[observed_target_stale] The control is stale or absent; observe again: none of the {frames} frame(s) on {origin} holds a control with this description now{target}: {frames} frame(s) searched, {skipped} on other origins skippedobserve the page again and name the control by the description, with its [n] index, the new observation printsrefused, exit 2, HTTP 403tests/browser/controls-failures.mjs::a_control_the_page_replaced_is_stale
observed-target-framesresolving the observed control {target} on {url}[observed_target_ambiguous] The control matches multiple frames; use a frame-specific description: {count} frames hold it{target}: frames {frames}observe the page again and name the control by the description, with its [n] index, the new observation printsrefused, exit 2, HTTP 403tests/browser/controls-failures.mjs::a_description_two_frames_share_is_refused
selector-target-invalidresolving the selector {target} on {url}[selector_target_invalid] Cannot resolve {target}: the browser refused the selector in frame {frame}; no pointer input was sentframe {frame}: {answer}name the control with a selector the browser takes (css=, xpath=, text=, id=, or button[label="..."]), or by its observed descriptionrefused, exit 2, HTTP 403tests/browser/controls-failures.mjs::a_selector_the_browser_refuses_is_named
selector-target-ambiguousresolving the selector {target} on {url}[selector_target_ambiguous] Multiple visible controls match {target}; no pointer input was sent{visible} visible of {count} matching element(s) in {frames} frame(s)narrow the selector to one visible control, or name it by its observed description with its [n] indexrefused, exit 2, HTTP 403tests/browser/controls-failures.mjs::a_selector_two_visible_controls_match_is_refused
selector-target-absentresolving the selector {target} on {url}[selector_target_absent] No visible control matches {target}; no pointer input was sent. Use a current observed control or a correct selector{count} matching element(s) in {frames} frame(s), none visibleobserve the page again and name the control by the description, with its [n] index, the new observation printsrefused, exit 2, HTTP 403tests/browser/controls-failures.mjs::a_selector_no_visible_control_matches_is_refused

session#

51 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
proxy-unavailableresolving the proxy {requested} for {target}the run asked for a proxy and none of its exits resolved, so the browser is not launched without onerequested {requested} {targetState}; persona {browser} on {os}; the pre-launch session_meta.json of {label} records the requestrun again once a {requested} exit for {target} answers, or start the session with another proxy requestinfra_down, exit 69, HTTP 503, retryabletests/session/launch-failures.mjs::a_session_whose_proxy_resolves_to_nothing_is_named
browser-path-override-retiredfinding the {engine} executable for session {label}CHROMIUM_PATH is set, and an explicit browser path override is retired: a browser is launched only from the selected, checksum-verified weles-{engine} releaseCHROMIUM_PATH={path}unset CHROMIUM_PATH; pin the release with WELES_{ENGINE}_RELEASE_VERSION and WELES_{ENGINE}_RELEASE_SHA256, or let the host selection record name itconfig, exit 1, HTTP 503tests/session/launch-failures.mjs::a_session_with_a_browser_path_override_is_refused
profile-platform-unnamedfiling the browser profile of account session ACCOUNT_IDACCOUNT_PROFILE_PLATFORM_UNNAMED: an account session files its browser profile under its platform, and neither WSession.start platform, the ACTION it runs, nor targetHost names oneplatform {platform}; ACTION {action}; targetHost {targetHost}pass platform to WSession.start (or targetHost), or run it under an ACTION whose first word is the platformrefused, exit 1, HTTP 403tests/session/launch-failures.mjs::an_account_session_without_a_platform_is_refused
profile-existsmaking a fresh browser profile at {directory}WELES_FRESH_PROFILE=1 asks for a fresh browser profile, and the profile directory of this account already exists, so the run would not start fresh{directory} exists (account key {accountKey}, platform {platform}, browser {browser})remove {directory} to start the account from a fresh profile, or unset WELES_FRESH_PROFILE to reuse itrefused, exit 1, HTTP 403tests/session/launch-failures.mjs::a_fresh_profile_that_already_exists_is_refused
profile-unmade{step} the browser profile directory {path}the browser profile directory cannot be made owner-only: a file stands on its path, or this user may not write {root}{code}: {problem}; profile root from {rootSource}make {root} a directory this user may write (or name another with WELES_BROWSER_PROFILE_ROOT), then start the session againconfig, exit 1, HTTP 503tests/session/launch-failures.mjs::a_profile_root_that_is_a_file_is_named
operator-cdp-token-sharedreading the operator browser WELES_OPERATOR_CDP_URL namesWELES_OPERATOR_CDP_TOKEN holds the same secret as {sibling}, and one secret must not admit two servicesWELES_OPERATOR_CDP_TOKEN equals {sibling} ({bytes} bytes; the value is withheld)give WELES_OPERATOR_CDP_TOKEN a secret of its own (`openssl rand -hex 32` prints one) and the operator browser the same, then start againconfig, exit 1, HTTP 503tests/session/operator-cdp-failures.mjs::an_operator_token_shared_with_another_service_is_refused
operator-cdp-url-invalidreading the operator browser WELES_OPERATOR_CDP_URL namesWELES_OPERATOR_CDP_URL is not an absolute URL, so there is no browser endpoint to connect toWELES_OPERATOR_CDP_URL: {length} characters, scheme {scheme}, {userPart} (the value is withheld: it may hold a password)set WELES_OPERATOR_CDP_URL to the operator browser endpoint, wss://<host>/<path> or ws://127.0.0.1:<port>/<path> on loopbackconfig, exit 1, HTTP 503tests/session/operator-cdp-failures.mjs::an_operator_address_that_is_no_url_is_refused
operator-cdp-url-insecurereading the operator browser WELES_OPERATOR_CDP_URL namesWELES_OPERATOR_CDP_URL must use TLS, except for authenticated loopback (localhost or an address of one of this machine's internal network interfaces), and {endpoint} is neitherscheme {scheme}, host {host}, loopback {loopback}serve the operator browser over wss:// (or https://), or reach it on a loopback address with ws://config, exit 1, HTTP 503tests/session/operator-cdp-failures.mjs::an_operator_address_without_tls_is_refused
operator-cdp-url-extrasreading the operator browser WELES_OPERATOR_CDP_URL namesWELES_OPERATOR_CDP_URL must not contain credentials, query, or fragment: the token is WELES_OPERATOR_CDP_TOKEN, and anything else in the address would be sent to the browser endpoint{endpoint} carries {extras}remove {extras} from WELES_OPERATOR_CDP_URL and put the secret in WELES_OPERATOR_CDP_TOKENconfig, exit 1, HTTP 503tests/session/operator-cdp-failures.mjs::an_operator_address_with_credentials_is_refused
protocol-session-absentattaching the protocol observers of session {label}the protocol setup of the session ended without a protocol session and without saying why, a defect of the release: the constructor records either one or its failuresession {label}: no protocol session, no attach errorrun the session again; if it repeats, report it with the run's session_meta.json and the [wsession] lines of its logunknown, exit 1, HTTP 500tests/session/launch-failures.mjs::a_protocol_setup_that_names_nothing_is_named
context-protocol-unavailableopening a protocol session on the page of session {label}the browser context does not expose newCDPSession: the engine is not Chromium, so the protocol observers (proxy bytes, network capture) have nothing to attach tobrowser {browser}; context without newCDPSessionrun sessions that need the protocol observers in weles-chromium (browser chromium)config, exit 1, HTTP 503tests/session/launch-failures.mjs::a_context_without_a_protocol_session_is_named
sessions-not-mapreading the saved browser sessions in the vault setting browser_sessionsthe vault setting browser_sessions does not map session labels to cookie lists, and answering it as empty would make the next save drop every other labelit holds {shape}{labels}rewrite the value_json of the setting record browser_sessions as {"<label>": [<cookie>, ...]}, or remove that record to start with no saved sessions; `stado credentials ls --json` lists the records of the vault Weles usesconfig, exit 1, HTTP 503tests/session/cookies-failures.mjs::saved_sessions_that_are_no_map_are_refused
cookies-unansweredcapturing the cookies of session {label}Network.getAllCookies answered no cookies list for session {label}; the saved session is kept, since saving none would sign the account out of every later runthe answer is {shape}save the session again once its page is open; the browser answers the list only while its context livesunknown, exit 1, HTTP 500tests/session/cookies-failures.mjs::a_browser_that_answers_no_cookie_list_is_named
cookies-incompleteputting the saved cookies of session {label} into the browsersession {label} in the vault setting browser_sessions holds cookies without a name, value or domain, which Playwright cannot set, and a session missing one of its cookies signs in as nobody{count} of {total} cookies lack one: {cookies}sign the session in again and save it, which rewrites its cookies wholeconfig, exit 1, HTTP 503tests/session/cookies-failures.mjs::a_saved_cookie_without_its_domain_is_refused
persona-unsignedsigning the persona a cookie jar is bound toCOOKIE_PERSONA_UNSIGNED: the persona carries no canvas seed to bind a cookie jar to, so it cannot be told from another personapersona fields: {fields}generate the persona through the persona generator, which gives every persona a canvas seedrefused, exit 1, HTTP 403tests/session/cookies-failures.mjs::a_persona_without_a_canvas_seed_is_refused
proxy-binding-unparsedsigning the proxy a cookie jar is bound tothe {form} the jar is bound to is not a URL, so it names no host and port to sign{form}: {length} characters, {userPart} (the value is withheld: it may hold a password)give the proxy as scheme://user:password@host:port, or as a record of host and portconfig, exit 1, HTTP 503tests/session/cookies-failures.mjs::a_proxy_that_is_no_url_is_refused
click-target-emptyclicking on {url}[target_empty] A click requires a non-empty target; no pointer input was senttarget {target}name the control to click: its observed description, a selector, or its textrefused, exit 2, HTTP 403tests/session/input-failures.mjs::a_click_without_a_target_is_refused
fill-target-emptyfilling a field on {url}[target_empty] A fill requires a non-empty target; no input was senttarget {target}name the field to fill: its label, placeholder, form name or a selectorrefused, exit 2, HTTP 403tests/session/input-failures.mjs::a_fill_without_a_target_is_refused
input-target-stalefilling {target} on {url}[input_target_stale] The field disappeared before literal input: the page replaced or removed it after it was found{target} found by {foundBy}, then gonewait for the page to settle (wait_for the field), then fill againrefused, exit 1, HTTP 403tests/session/input-failures.mjs::a_field_the_page_removes_before_input_is_named
fill-origin-not-webfilling {target}fill requires an HTTP(S) origin, and the page is a {protocol} page, where no web origin bounds what is typedpage {page}navigate to the http(s) page that holds the field, then fillrefused, exit 1, HTTP 403tests/session/input-failures.mjs::a_fill_on_a_page_that_is_no_web_page_is_refused
focus-element-absentchecking the focused field before typing on {url}literal input requires an observable focused element, and after the click nothing on the page holds focus, so what would be typed into cannot be checkeddocument.activeElement is none in frame {frame}click the field itself (name it by its label or a selector) before typingrefused, exit 1, HTTP 403tests/session/input-failures.mjs::typing_with_nothing_focused_is_refused
focus-frame-absentchecking the focused field before typing on {url}literal input requires an observable focused frame, and the page answered no main frame to read focus in, a state a live page does not reachpage {url} without a main frameopen the page again and repeat the step; if it repeats, report it with the run logunknown, exit 1, HTTP 500tests/session/input-failures.mjs::a_page_without_a_main_frame_is_named
existing-text-unselectedselecting the text {target} holds before typing on {url}the keyboard could not select the text the field holds, and typing after a failed select-all would append to it, so nothing is typedthe engine said: {answer}clear the field another way (fill it by its label or selector) and fill againrefused, exit 1, HTTP 403tests/session/input-failures.mjs::a_field_whose_text_cannot_be_selected_is_named
selector-unmatchedfilling the field {css} on {url}no element matches {css} on the page; nothing was filled0 elements match {css} on {url}observe the page and name the field by a selector it has, or wait for it firstnot_found, exit 1, HTTP 404tests/session/input-failures.mjs::a_fill_of_a_selector_nothing_matches_is_named
account-unpatchedupdating account {account}account {account} was not updated: writing its {fields} raised an error the vault layer declares no cause for, and the token the run just received is not kept{answer}run `weles doctor` to see whether the vault Weles uses answers, then run the step again; the observed error names what the write metunknown, exit 1, HTTP 500tests/session/input-failures.mjs::an_account_update_the_vault_refuses_is_named
identity-unavailablefilling {target} from the generated identitygenerated identity is unavailable: the session generated none, since it was started without a platform and no step called generateIdentityfield {field}; session {label} holds no identitystart the session with its platform, or generate the identity firstrefused, exit 1, HTTP 403tests/session/input-failures.mjs::an_identity_fill_without_an_identity_is_refused
identity-placeholder-unresolvedputting the session values into a step argumentunresolved generated identity placeholder: the argument names a $<PLATFORM>_NEW_<FIELD> value this session did not generateunresolved {placeholders}; generated for {generated}generate the identity of that platform first, or name the platform the session generatedrefused, exit 1, HTTP 403tests/session/input-failures.mjs::a_placeholder_of_an_identity_never_generated_is_refused
sms-order-missingreading the code texted to the session numberSMS_ORDER_MISSING: this session rented no number (checkSms rents one), so there is no number a code was texted tosession {label}: no rented numbercall checkSms for the service and country first, then textedCoderefused, exit 1, HTTP 403tests/session/input-failures.mjs::a_texted_code_without_a_rented_number_is_refused
credential-origin-not-webfilling {target} from {source}credential fill requires an HTTP(S) origin, and the page is a {protocol} page, which bounds no web origin a capability is minted forpage {page}; the capability was not consumednavigate to the http(s) sign-in page that holds the field, then fill itrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::a_credential_fill_on_a_page_that_is_no_web_page_is_refused
credential-target-unusablefilling the {fieldClass} field {target} at {origin}[credential_target_unusable] {target} is not a visible editable field; capability not consumedvisible {visible}, editable {editable}wait for the field to be shown and enabled (wait_for it), then fill it againrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::a_hidden_credential_field_is_refused
credential-control-not-elementreading the markup of the control bound to {target}the bound control is a {node} node, not an element, so it has no markup to declare a credential class{target} bound to a {node} nodename the input element itself: observe the page and use its description, or a selector of the inputrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::a_target_bound_to_a_text_node_is_refused
credential-target-mismatchfilling the {fieldClass} field {target} at {origin}[credential_target_mismatch] {target} is a {type} control with autocomplete {autocomplete}; a {fieldClass} goes only into a field whose markup declares input type {types} or autocomplete {names}{plainText}. The capability was not consumed{target}: type {type}, autocomplete {autocomplete}name the field whose markup declares a {fieldClass} (observe the page for it), or fill this field with the class its markup declaresrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::a_credential_into_a_field_of_another_class_is_refused
literal-into-credential-fieldtyping literal text into {target}[credential_target] a {type} control with autocomplete {autocomplete} declares a {fieldClass} field; credential fields require fill_credential with a capability reference{target}: type {type}, autocomplete {autocomplete}fill the field with fill_credential and a capability reference for the {fieldClass}, never with literal textrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::literal_text_into_a_password_field_is_refused
credential-target-ambiguousfilling the {fieldClass} field {target} at {origin}[credential_target_ambiguous] Multiple editable fields match {target}; capability not consumed{target} matched by {query} in {frames} frame(s) of {origin}name the one field: observe the page and use its description with its [n] index, or a selector only it matchesrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::a_target_two_editable_fields_match_is_refused
credential-material-emptytyping into the credential field {target} at {origin}the capability redeemed empty credential material, so there is nothing to type; the capability was spent and must not be retriedthe value is empty ({source})store the credential in the item the capability names, then mint a new capability for itrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::an_empty_credential_is_refused
credential-field-changedtyping into the credential field {target} at {origin}the bound page or field changed before input: the field left the document, or the page moved to another origin; the capability was spent and must not be retriedfield connected {connected}; field origin {fieldOrigin}; page origin {pageOrigin}wait for the sign-in page to settle, then fill again with a new capabilityrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::a_field_the_page_replaces_before_input_is_named
credential-not-retainedtyping into the credential field {target} at {origin}the bound field did not retain the credential after typing: the page rewrote or cleared it, or limits its length; the capability was spent and must not be retriedthe field holds another value after typing ({length} characters typed; neither value is shown)check the field's maxlength and the page's input handling, then fill again with a new capabilityrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::a_field_that_drops_the_typed_value_is_named
credential-typing-threwtyping into the credential field {target} at {origin}typing into the field or reading it back threw: the field left the page, the page navigated, or the browser closed while typing; the capability was spent and must not be retried{thrown}; its message is withheld because it may hold the credentialopen the sign-in page again and fill the field with a new capabilityrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::a_browser_closed_while_typing_is_named
identity-input-failedfilling {target} at {origin} with the generated {field}identity {field} input failed: the field could not be found, focused or typed into; the capability was spent and must not be retried{thrown}; its message is withheld because it may hold the valueobserve the page and name the field by its description or a selector, then fill it againrefused, exit 1, HTTP 403tests/session/credential-fill-failures.mjs::an_identity_field_that_refuses_input_is_named
har-unreadwithholding the request bodies of the HAR {path}the HAR exists and cannot be read; the HAR was removed rather than kept with request bodies a password may be in{code}: {problem}make the recordings directory readable by the worker user; the next run records a new HARinfra_down, exit 69, HTTP 503, retryabletests/session/capture-failures.mjs::a_har_that_cannot_be_read_is_removed_and_named
har-not-jsonwithholding the request bodies of the HAR {path}the HAR is not one JSON document: Playwright had not sealed it, or it was cut off; the HAR was removed rather than kept with request bodies a password may be in{bytes} bytes, not JSON (the parser's words are withheld: they quote the HAR, which may hold a typed password)close the session before its HAR is scrubbed; a run that ends normally closes its context firstunknown, exit 1, HTTP 500tests/session/capture-failures.mjs::a_har_that_is_not_json_is_removed_and_named
har-entries-absentwithholding the request bodies of the HAR {path}the HAR holds no log.entries array, so its request bodies cannot be found; the HAR was removed rather than kept with request bodies a password may be inthe document holds {shape}record the HAR with Playwright (recordHar), which writes log.entriesunknown, exit 1, HTTP 500tests/session/capture-failures.mjs::a_har_without_entries_is_removed_and_named
har-unrewrittenwithholding the request bodies of the HAR {path}the scrubbed HAR could not be written beside it and moved into place; the HAR was removed rather than kept with request bodies a password may be in{step} {scratch}: {code}: {problem}free space on the disk of the recordings directory, or make it writable by the worker userinfra_down, exit 69, HTTP 503, retryabletests/session/capture-failures.mjs::a_har_whose_rewrite_is_refused_is_removed_and_named
har-unremovedremoving the HAR {path} whose request bodies could not be withheldthe HAR could not be scrubbed and could not be removed either, so it stays in the recordings with request bodies a typed password may be inremoval: {code}: {problem}; why it was removed: {why}remove {path} by hand now (rm), then make the recordings directory writable by the worker userinfra_down, exit 69, HTTP 503, retryabletests/session/capture-failures.mjs::a_har_that_cannot_be_removed_is_named
artifact-circularwriting the instrumentation artifact {path}the value holds itself at {member}, which JSON cannot carry (Converting circular structure to JSON); a defect of the recorder that built ita circular structure at {member}; {path} is left as written so farreport the artifact {path} and the recorder that built it, naming the member aboveunknown, exit 1, HTTP 500tests/session/capture-failures.mjs::a_circular_artifact_is_named_with_its_member
artifact-unwritten{step} the instrumentation artifact {path}the artifact file could not be {stepDone}: its directory is missing or not writable, or the disk is full{code}: {problem}make the recordings directory exist and be writable by the worker user, and free space on its diskinfra_down, exit 69, HTTP 503, retryabletests/session/capture-failures.mjs::an_artifact_whose_directory_is_missing_is_named
instrumentation-flush-unavailablereading the instrumentation log of frame {frame}weles.inst.flush is unavailable in the frame: the instrumentation script was not injected there, or the page replaced itframe {frame}: the engine said: {answer}keep page diagnostics on for the run (WELES_PAGE_DIAGNOSTICS unset, WELES_NO_INSTRUMENT unset); the other frames are still readunknown, exit 1, HTTP 500tests/session/capture-failures.mjs::a_frame_without_the_instrumentation_is_named
instrumentation-log-not-listreading the instrumentation log of frame {frame}weles.inst.flush returned a non-array log: the page overwrote the instrumentation global, or another release injected itframe {frame}: {shape}run the page again; a page that defines Symbol.for("weles.inst") itself cannot be recordedunknown, exit 1, HTTP 500tests/session/capture-failures.mjs::a_frame_whose_log_is_no_list_is_named
instrumentation-log-not-jsonreading the instrumentation log of frame {frame}weles.inst.flush answered text that is not JSON, so the frame log is not keptframe {frame}: {bytes} characters, not JSON (the parser's words are withheld: they quote the page's log)run the page again; if it repeats, report the frame and the run logunknown, exit 1, HTTP 500tests/session/capture-failures.mjs::a_frame_whose_log_is_no_json_is_named
step-record-unwrittenrecording that step {step} failed without its artifactsstep {step} failed and its missing-artifact record could not be written either, so the run directory says nothing of why its artifacts are missingthe step failed: {stepReason}; and the record write failed: {ledgerReason}make the run directory writable by the worker user and free space on its disk, then run the trajectory againinfra_down, exit 69, HTTP 503, retryabletests/session/capture-failures.mjs::a_step_whose_failure_record_cannot_be_written_is_named
artifact-record-unwrittenrecording that the {phase} {missing} of step {step} is missingthe {phase} {missing} of step {step} could not be taken, and the record naming why could not be written either, so the run directory would say nothing of the gapthe record write failed: {ledgerReason}make the run directory writable by the worker user and free space on its disk, then run the trajectory againinfra_down, exit 69, HTTP 503, retryabletests/session/capture-failures.mjs::a_step_whose_artifact_record_cannot_be_written_is_named

agent#

68 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
inference-unansweredasking a model through `{command}`no inference alternative in Stado's selected order answered Weles's request: each one is named below with why it did not`{command}` exited {status}; Stado cause {functionality}.{stado} ({code}, retryable {retryable}): {answer}; alternatives: {alternatives}repair what Stado names for each alternative ({fix}); `stado capabilities resolve inference --consumer weles` shows them again, and a run someone attends answers the kept request with `stado capabilities attestation record inference --consumer weles <request>` and WELES_AWAIT_STATEMENT=1infra_down, exit 69, HTTP 503, retryabletests/agent/inference-failures.mjs::a_model_request_no_alternative_answers_names_each
inference-refusedasking a model through `{command}`Stado refused the request for a declared cause other than no alternative answering: its cause id and fix below say which`{command}` exited {status}; Stado cause {functionality}.{stado} ({code}, retryable {retryable}): {answer}do what Stado says ({fix}); `stado errors show {functionality}` lists every way it refusesrefused, exit 1, HTTP 403tests/agent/inference-failures.mjs::a_request_stado_refuses_relays_its_cause
inference-unenvelopedasking a model through `{command}`Stado exited refusing without the declared JSON envelope --json promises: a Stado too old for an option Weles passes (such as --operation), or one that failed before its own error handling`{command}` exited {status} and printed {printed} characters that are no Stado envelope; its standard error ends: {said}run `stado capabilities call --help` to see the options this Stado takes, and update Stado to the release named as minimum_stado_version in Weles's release manifest when it lacks oneconfig, exit 1, HTTP 503tests/agent/inference-failures.mjs::a_stado_without_the_operation_is_named
inference-call-killedasking a model through `{command}`the Stado process was ended by a signal before it answered: the host stopped it, it ran out of memory, or the run was interrupted`{command}` ended on {signal}; its standard error ends: {said}run the request again; `stado capabilities resolve inference --consumer weles` shows whether an alternative answers nowinfra_down, exit 69, HTTP 503, retryabletests/agent/inference-failures.mjs::a_stado_ended_by_a_signal_is_named
inference-answer-not-jsonreading what `{command}` printedStado exited 0 and what it printed on standard output is not JSON: an older Stado that ignores --json, or something else writing to its standard output{printed} characters; the parser said: {problem}run `stado --version` and update Stado to the release named as minimum_stado_version in Weles's release manifest, then run againconfig, exit 1, HTTP 503tests/agent/inference-failures.mjs::a_stado_printing_no_json_is_named
inference-answer-absentreading what `{command}` printedStado exited 0 with a JSON document that carries no answer member, where --json prints the resolution beside the answerthe document holds: {members}run `stado --version` and update Stado to the release named as minimum_stado_version in Weles's release manifest, then run againconfig, exit 1, HTTP 503tests/agent/inference-failures.mjs::a_stado_printing_no_answer_is_named
model-image-unreadablebuilding the model request for {model}image {index} of the request holds no picture sharp can read, so its media type cannot be named: the screenshot or capture that made it was cut short or is not an imageimage {index}: {bytes} bytes; sharp said: {problem}take the screenshot or capture again; the bytes it gave are kept where the caller recorded themunknown, exit 1, HTTP 500tests/agent/model-failures.mjs::an_image_that_is_no_picture_is_named
model-image-format-otherbuilding the model request for {model}image {index} of the request is {format}, a format the chat API takes no data URL ofimage {index}: {format}, {bytes} bytes; the request takes {accepted}capture the page as one of {accepted} (a Playwright screenshot is png or jpeg) and ask againunknown, exit 1, HTTP 500tests/agent/model-failures.mjs::an_image_of_another_format_is_named
model-completion-shapereading the answer {provider} gave {model} through `{route}`the answer is no chat completion: it carries no list of choices, so neither a message nor a function call can be read from itthe answer holds: {members}run `stado capabilities inference` to see which alternative served weles; a statement recorded for this request must be the completion text, recorded again with `stado capabilities attestation record`unknown, exit 1, HTTP 500tests/agent/model-failures.mjs::an_answer_that_is_no_completion_is_named
model-function-otherreading the answer {provider} gave {model} through `{route}`the request declared functions and required one call, and the answer did not call exactly one of them with its arguments as textcalled: {called}; declared: {declared}; finish_reason {finish}ask again; a model that keeps answering in text needs an alternative that supports function calling, chosen with `stado capabilities select inference --order ...`unknown, exit 1, HTTP 500tests/agent/model-failures.mjs::an_answer_calling_no_declared_function_is_named
model-content-emptyreading the answer {provider} gave {model} through `{route}`the answer carries no text: the model stopped before writing any ({bound})finish_reason {finish}; usage {usage}ask again; when finish_reason is length, the request needs a larger max_tokens or a shorter promptunknown, exit 1, HTTP 500tests/agent/model-failures.mjs::an_answer_without_text_is_named
draft-not-jsonreading the trajectory draft {provider} wrote through {model} for the objective {objective}the arguments of its write_trajectory call are not JSON{bytes} characters; the parser said: {problem}; the arguments: {raw}run the task again, or start it with WELES_DISABLE_TRAJECTORY_WRITER=1 to let the objective alone guide the agentunknown, exit 1, HTTP 500tests/agent/draft-failures.mjs::a_draft_that_is_not_json_fails_the_run
draft-not-objectreading the trajectory draft {provider} wrote through {model} for the objective {objective}the arguments of its write_trajectory call are {kind}, not an object of steps and notesthe arguments: {raw}run the task again, or start it with WELES_DISABLE_TRAJECTORY_WRITER=1 to let the objective alone guide the agentunknown, exit 1, HTTP 500tests/agent/draft-failures.mjs::a_draft_that_is_no_object_fails_the_run
draft-field-not-listreading the trajectory draft {provider} wrote through {model} for the objective {objective}its {field} is {kind}, where write_trajectory declares a list of stringsthe arguments: {raw}run the task again, or start it with WELES_DISABLE_TRAJECTORY_WRITER=1 to let the objective alone guide the agentunknown, exit 1, HTTP 500tests/agent/draft-failures.mjs::a_draft_field_that_is_no_list_fails_the_run
draft-entry-blankreading the trajectory draft {provider} wrote through {model} for the objective {objective}entry {position} of its {field} is {kind}, where write_trajectory declares nonblank stringsthe arguments: {raw}run the task again, or start it with WELES_DISABLE_TRAJECTORY_WRITER=1 to let the objective alone guide the agentunknown, exit 1, HTTP 500tests/agent/draft-failures.mjs::a_draft_entry_that_is_blank_fails_the_run
draft-emptyreading the trajectory draft {provider} wrote through {model} for the objective {objective}it holds no step and no note, so it would guide the agent with nothingthe arguments: {raw}run the task again, or start it with WELES_DISABLE_TRAJECTORY_WRITER=1 to let the objective alone guide the agentunknown, exit 1, HTTP 500tests/agent/draft-failures.mjs::a_draft_without_a_step_fails_the_run
draft-recording-unreadablereading the Chrome DevTools Recorder recording {file} WELES_TRAJECTORY_RECORDING names as the trajectory draftthe file cannot be read as a Recorder JSON export{problem}export the recording again from Chrome DevTools → Recorder → Export as JSON, or unset WELES_TRAJECTORY_RECORDING to let the writer draft the trajectoryunknown, exit 1, HTTP 500tests/agent/draft-failures.mjs::a_recording_that_cannot_be_read_fails_the_run
draft-recording-emptyreading the Chrome DevTools Recorder recording {file} WELES_TRAJECTORY_RECORDING names as the trajectory draftits steps hold no navigation, click, change or key step, so it would guide the agent with nothing{steps} steps, of the types {types}export the recording again from Chrome DevTools → Recorder → Export as JSON, or unset WELES_TRAJECTORY_RECORDING to let the writer draft the trajectoryunknown, exit 1, HTTP 500tests/agent/draft-failures.mjs::a_recording_without_a_step_fails_the_run
flows-login-url-unreadreading the address of the login page before credentials are typedthe browser page did not answer its address: the page or its browser closed, or the connection to it brokethe page said: {problem}run the login again; `weles doctor` shows whether the browser runtime answersinfra_down, exit 69, HTTP 503, retryabletests/agent/flows-failures.mjs::a_login_page_that_gives_no_address_is_named
flows-login-url-emptyreading the address of the login page before credentials are typedthe page answered an empty address, so its host cannot be checked before credentials are typedaddress: {url}navigate the page to the login form first, then run the loginunknown, exit 1, HTTP 500tests/agent/flows-failures.mjs::a_login_page_with_an_empty_address_is_refused
flows-login-url-relativechecking the host of the login page {url} before credentials are typedthe address is not an absolute URL, so its host cannot be checkedaddress {url}; the URL parser said: {problem}navigate the page to the login form at its absolute https address, then run the loginunknown, exit 1, HTTP 500tests/agent/flows-failures.mjs::a_login_page_whose_address_is_relative_is_refused
flows-login-apple-refusedtyping credentials into the login page at {host}the generic vision login does not type passwords into Apple's sign-in; Apple accounts sign in only through the owner-authorized apple_login flowhost {host}run `weles login --provider apple --confirm "AUTHORIZE ONE APPLE LOGIN" --execution-host <host> --expires-in-minutes <n>` insteadrefused, exit 2, HTTP 403tests/agent/flows-failures.mjs::an_apple_login_page_is_refused
flows-login-navigation-failedwaiting for the page to leave {url} after the login was submittedthe browser stopped answering while the page was watched: the page closed, crashed or its connection brokethe browser said: {problem}run the login again; the run recording shows the page at the moment it was submittedinfra_down, exit 69, HTTP 503, retryabletests/agent/flows-failures.mjs::a_login_whose_page_closes_after_submit_is_named
flows-field-unstatedreading an account value with FetchAccountValuethe caller did not state {name}, which the flow never assumes{name}: {given}pass {name} to FetchAccountValue (service, url, what, osTarget and trajectoryCacheDir are all required)config, exit 2, HTTP 503tests/agent/flows-failures.mjs::a_fetch_without_a_stated_field_is_refused
flows-login-secret-absentsigning in to {service} to read {what}{service} shows a login page, and the Weles service secret {secret} grants no {missing}secret {secret}: {missing} absentstore the {missing} of the {service} account in the Skarbiec item the Weles service secret {secret} names, then run againconfig, exit 1, HTTP 503tests/agent/flows-failures.mjs::a_login_page_without_its_secret_is_named
flows-login-not-reachedsigning in to {service} with {secret}the login form was filled and submitted and the page did not reach the account: the credentials are wrong, or the site asked for a step the flow does not takethe page stayed at {url}check the credentials in {secret}, sign in once through `weles open {url} --os macos --browser chromium` to see what the site asks, then run againrefused, exit 1, HTTP 403tests/agent/flows-failures.mjs::a_login_that_does_not_reach_the_account_is_named
flows-cache-unreadreading the learned route of {service} from {path}the file exists and the system refused to read it ({errno}): it is not readable by the worker user, or it is a directory{path}: {problem}give the worker's user read access to {path}, or remove it; the next run rediscovers the route and learns it againconfig, exit 1, HTTP 503tests/agent/flows-failures.mjs::a_learned_route_that_cannot_be_read_is_named
flows-cache-not-jsonreading the learned route of {service} from {path}the file is not JSON: it was cut short while written, or something else wrote it{bytes} characters; the parser said: {problem}remove {path}; the next run rediscovers the route and learns it againconfig, exit 1, HTTP 503tests/agent/flows-failures.mjs::a_learned_route_that_is_not_json_is_named
flows-cache-shapereading the learned route of {service} from {path}the file holds JSON that is no learned route (service, finalUrl, selector, lastSuccess, lastValue)it holds: {members}remove {path}; the next run rediscovers the route and learns it againconfig, exit 1, HTTP 503tests/agent/flows-failures.mjs::a_learned_route_of_another_shape_is_named
flows-value-mistypedreading {what} off the pagethe model called value with {kind} where the declared function takes {expected}value: {value}ask again; a model that keeps answering another type needs a clearer description of {what}unknown, exit 1, HTTP 500tests/agent/flows-failures.mjs::a_value_of_another_type_is_named
tool-argument-not-textreading the {tool} call the model madeinvalid {key}: expected a string, received {kind}; {tool} takes {key} as text{tool} arguments: {keys}call {tool} again with {key} as a stringrefused, exit 2, HTTP 403tests/agent/tools-failures.mjs::a_tool_argument_that_is_not_text_is_refused
tool-wait-state-invalidreading the {tool} call the model madeinvalid state: {state} is not one of {states}state {state}call wait_for with state one of {states}, or leave it out to wait until visiblerefused, exit 2, HTTP 403tests/agent/tools-failures.mjs::a_wait_for_an_unknown_state_is_refused
tool-capability-malformedreading the {tool} call the model madeinvalid capability reference: a capability is an object of capability_id, purpose and resource as text and target "weles", and this one {problem}capability keys: {keys}pass the capability object exactly as it was handed to the run, without changing or adding a memberrefused, exit 2, HTTP 403tests/agent/tools-failures.mjs::a_capability_of_another_shape_is_refused
tool-capability-purpose-unknownreading the {tool} call the model madeinvalid capability reference: its purpose {purpose} is not one Weles redeems ({purposes})purpose {purpose}pass the capability the run was handed for this field; Weles redeems only {purposes}refused, exit 2, HTTP 403tests/agent/tools-failures.mjs::a_capability_of_an_unknown_purpose_is_refused
tool-field-class-unknownreading the {tool} call the model madeinvalid field_class: {given} is not a credential class fill_credential fills ({classes})field_class {given}call fill_credential with field_class one of {classes}refused, exit 2, HTTP 403tests/agent/tools-failures.mjs::a_credential_fill_of_an_unknown_class_is_refused
tool-identity-field-unknownreading the {tool} call the model madeinvalid identity field: {given} is not a field of the generated identity ({fields})field {given}call fill_identity with field one of {fields}refused, exit 2, HTTP 403tests/agent/tools-failures.mjs::an_identity_fill_of_an_unknown_field_is_refused
tool-storage-class-unknownreading the {tool} call the model madeinvalid credential storage field_class: {given} is not one store_credential keeps (token or api-key)field_class {given}call store_credential with field_class token or api-keyrefused, exit 2, HTTP 403tests/agent/tools-failures.mjs::a_credential_store_of_an_unknown_class_is_refused
tool-unknownrunning the tool the model namedUNKNOWN_TOOL: {tool} is not one of the declared browser toolstool {tool}; declared: {tools}call one of the declared browser tools: {tools}refused, exit 2, HTTP 403tests/agent/tools-failures.mjs::a_tool_no_declaration_names_is_refused
decision-unansweredreading step {step} the model chose for {goal}the model call gave no function arguments, so there is no next step to runthe model call said: {answer}run `stado capabilities resolve inference --consumer weles` to see which model route answers, then run the task againinfra_down, exit 69, HTTP 503, retryabletests/agent/decision-failures.mjs::a_model_that_answers_nothing_gives_up_naming_it
decision-function-undeclaredreading step {step} the model chose for {goal}the model named the function {name}, which no browser tool declaresfunction {name}; declared: {tools}run the task again; a model that keeps naming another function needs a prompt that lists the tools it may callunknown, exit 1, HTTP 500tests/agent/decision-failures.mjs::a_model_naming_an_undeclared_function_gives_up
decision-arguments-not-jsonreading step {step} the model chose for {goal}the arguments the model gave {name} are not JSON{bytes} characters; the parser said: {problem}run the task again; the step record loop_step{step}.json keeps the raw answerunknown, exit 1, HTTP 500tests/agent/decision-failures.mjs::a_model_giving_arguments_that_are_not_json_gives_up
decision-arguments-not-objectreading step {step} the model chose for {goal}{name} arguments must be an object, and the model gave {kind}arguments: {kind}run the task again; the step record loop_step{step}.json keeps the raw answerunknown, exit 1, HTTP 500tests/agent/decision-failures.mjs::a_model_giving_arguments_that_are_no_object_gives_up
decision-argument-names-otherreading step {step} the model chose for {goal}{name} argument names: unknown=[{unknown}], missing=[{missing}]; {name} takes {taken}arguments given: {given}run the task again; {name} takes exactly {taken}unknown, exit 1, HTTP 500tests/agent/decision-failures.mjs::a_model_giving_other_argument_names_gives_up
loop-max-steps-unsetstarting a browser task at {url}WELES_AGENT_MAX_STEPS is not set and the caller named no step limit, so nothing bounds how many model steps the task may takeWELES_AGENT_MAX_STEPS unset; {observed} initialization steps observed; the browser was not drivenset WELES_AGENT_MAX_STEPS to a whole number above zero in the environment the run starts with (the worker service unit, or the run's own environment), then run the task againconfig, exit 1, HTTP 503tests/agent/loop-failures.mjs::a_task_without_a_step_limit_is_refused
loop-max-steps-invalidstarting a browser task at {url}WELES_AGENT_MAX_STEPS is {value}, which is not a whole number above zeroWELES_AGENT_MAX_STEPS={value} ({length} characters); the browser was not drivenset WELES_AGENT_MAX_STEPS to a whole number above zero in the environment the run starts with (the worker service unit, or the run's own environment), then run the task againconfig, exit 1, HTTP 503tests/agent/loop-failures.mjs::a_step_limit_that_is_no_whole_number_is_refused
loop-pages-closedrunning step {step} of the browser task at {url}every page of the browser session is closed, so there is no page to observe or act on: the site closed its last tab, or the browser ended{pages} pages known to the session, all closed; {taken} steps taken; last address {last}run the task again; when the site closes its window after a step, end the task with done at that step insteadunknown, exit 1, HTTP 500tests/agent/loop-failures.mjs::a_task_whose_pages_all_close_is_named
loop-replay-endedrunning step {step} of the browser task at {url}the replayed flow ran all its {steps} steps and none of them was done, and a replay-only run takes no step the model choosesreplayed {steps} steps; last tool {last}record the flow again with a run that is not replay-only, so its last step is doneunknown, exit 1, HTTP 500tests/agent/loop-failures.mjs::a_replay_without_done_is_named
loop-replay-step-failedreplaying step {step} ({tool}) of the flow at {url}the replayed step threw where the flow recorded it succeeding, and a replay-only run takes no other step: the page no longer matches the recording{tool} threw: {problem}record the flow again with a run that is not replay-only against the page as it is nowunknown, exit 1, HTTP 500tests/agent/loop-failures.mjs::a_replayed_step_that_fails_is_named
loop-decision-tool-absentrunning step {step} of the browser task at {url}the {source} decision for the step names no tool, so there is nothing to dispatchdecision members: {members}; tool is {kind}run the task again; a replayed flow holding such a step is recorded again with a run that is not replay-onlyunknown, exit 1, HTTP 500tests/agent/loop-failures.mjs::a_decision_naming_no_tool_is_refused
loop-decision-arguments-absentrunning step {step} of the browser task at {url}the {source} decision calls {tool} without an argument object, so the tool would be dispatched blankdecision members: {members}; args is {kind}run the task again; a replayed flow holding such a step is recorded again with a run that is not replay-onlyunknown, exit 1, HTTP 500tests/agent/loop-failures.mjs::a_decision_without_arguments_is_refused
loop-gave-uprunning step {step} of the browser task at {url}the model gave up on the goal: {reason}give_up at step {step} after {taken} steps; page {last}do what the reason asks (a person approves the step, the account is repaired, the goal is restated), then run the task againrefused, exit 1, HTTP 403tests/agent/loop-failures.mjs::a_model_that_gives_up_is_named
loop-gave-up-unsaidrunning step {step} of the browser task at {url}the model gave up on the goal without saying why: its give_up carries no reasongive_up at step {step} after {taken} steps with arguments {members}; page {last}run the task again; the step records of the run show what the page showed when the model gave uprefused, exit 1, HTTP 403tests/agent/loop-failures.mjs::a_model_that_gives_up_without_a_reason_is_named
loop-steps-exhaustedrunning the browser task at {url}the task took all {limit} steps its limit allows without the model calling done or give_up{limit} steps, {failed} of them failed; last tool {last} on {page}read the step records of the run for where it went round; raise WELES_AGENT_MAX_STEPS (or the caller's step limit) only when the goal needs more stepsunknown, exit 1, HTTP 500tests/agent/loop-failures.mjs::a_task_that_uses_up_its_steps_is_named
evidence-target-setting-unsetreading the browser-evidence target the run was admitted withbrowser-evidence target network binding is invalid: {name} is not set{name} unset or emptyset WELES_BROWSER_EVIDENCE_TARGET_ORIGIN, _HOST and _ADDRESSES_JSON as the admission states them (the worker sets them from the admitted task)config, exit 1, HTTP 503tests/agent/evidence-target-failures.mjs::a_target_without_its_origin_is_refused
evidence-target-addresses-not-jsonreading the browser-evidence target the run was admitted withbrowser-evidence target network binding is invalid: WELES_BROWSER_EVIDENCE_TARGET_ADDRESSES_JSON is not JSON{bytes} characters; the parser said: {problem}set WELES_BROWSER_EVIDENCE_TARGET_ADDRESSES_JSON to a JSON array of the admitted addresses, ["203.0.113.7"] sayconfig, exit 1, HTTP 503tests/agent/evidence-target-failures.mjs::target_addresses_that_are_not_json_are_refused
evidence-target-addresses-not-listreading the browser-evidence target the run was admitted withbrowser-evidence target network binding is invalid: WELES_BROWSER_EVIDENCE_TARGET_ADDRESSES_JSON is not a non-empty array of address stringsit holds {shape}set WELES_BROWSER_EVIDENCE_TARGET_ADDRESSES_JSON to a non-empty JSON array of address stringsconfig, exit 1, HTTP 503tests/agent/evidence-target-failures.mjs::target_addresses_that_are_no_list_are_refused
evidence-target-origin-invalidreading the browser-evidence target the run was admitted withbrowser-evidence target network binding is invalid: WELES_BROWSER_EVIDENCE_TARGET_ORIGIN {origin} {problem}origin {origin}; host {host}set WELES_BROWSER_EVIDENCE_TARGET_ORIGIN to the https origin alone (https://<host>, no path) on WELES_BROWSER_EVIDENCE_TARGET_HOSTconfig, exit 1, HTTP 503tests/agent/evidence-target-failures.mjs::a_target_origin_with_a_path_is_refused
evidence-target-hostname-emptyresolving the browser-evidence targetnetwork hostname is empty: "{hostname}" names no host to resolvehostname "{hostname}"set WELES_BROWSER_EVIDENCE_TARGET_ORIGIN, _HOST and _ADDRESSES_JSON as the admission states them (the worker sets them from the admitted task)config, exit 1, HTTP 503tests/agent/evidence-target-failures.mjs::a_target_with_an_empty_host_is_refused
evidence-target-hostname-unresolvedresolving the browser-evidence target {hostname}network hostname has no addresses: {hostname} did not resolve, so the run cannot be pinned to it{code}: {answer}check the name resolves on this host (`dig {hostname}`), then submit the task againinfra_down, exit 69, HTTP 503, retryabletests/agent/evidence-target-failures.mjs::a_target_that_does_not_resolve_is_named
evidence-target-url-invalidadmitting the browser-evidence target of a taskbrowser-evidence target must be public HTTPS without credentials, and the task names {problem}target {shown}submit the task with product_url an https URL without a user or passwordrefused, exit 2, HTTP 403tests/agent/evidence-target-failures.mjs::a_target_that_is_no_public_https_url_is_refused
evidence-target-dns-changedinstalling the browser-evidence policy of run {label}browser-evidence target DNS changed before browser policy installation: {hostname} resolves to other addresses than were admittedadmitted {admitted}; now {current}submit the task again, so it is admitted with the addresses the name resolves to nowrefused, exit 1, HTTP 403tests/agent/evidence-target-failures.mjs::a_target_whose_addresses_changed_is_refused
evidence-request-main-navigation-deniedadmitting the request {method} {url} of a browser-evidence runnon-network main-frame navigation denied: the page moved its main frame to a {protocol} document, which the target origin does not servemain-frame navigation to {protocol}nothing to change: the ledger keeps this withheld edge as evidence of what the page triedrefused, exit 1, HTTP 403tests/agent/evidence-target-failures.mjs::a_main_frame_navigation_to_a_data_url_is_withheld
evidence-request-not-httpadmitting the request {method} {url} of a browser-evidence runnon-HTTP(S) browser request denied: the page asked for {protocol}{credentials}, and only pinned HTTP(S) leaves the browserscheme {protocol}{credentials}nothing to change: the ledger keeps this withheld edge as evidence of what the page triedrefused, exit 1, HTTP 403tests/agent/evidence-target-failures.mjs::a_request_of_another_scheme_is_withheld
evidence-request-method-deniedadmitting the request {method} {url} of a browser-evidence runanonymous browser-evidence network policy permits only methods that carry no body (GET and HEAD), and the page sent {method}method {method}nothing to change: a browser-evidence run observes and never submits; the ledger keeps the withheld edgerefused, exit 1, HTTP 403tests/agent/evidence-target-failures.mjs::a_request_with_a_body_is_withheld
evidence-request-origin-otheradmitting the request {method} {url} of a browser-evidence runbrowser request left the exact admitted target origin: {origin} is not {target}origin {origin}; admitted {target}nothing to change: only the admitted origin is reached; the ledger keeps the withheld edgerefused, exit 1, HTTP 403tests/agent/evidence-target-failures.mjs::a_request_to_another_origin_is_withheld
evidence-request-dns-changedadmitting the request {method} {url} of a browser-evidence runtarget DNS differs from the admitted pinned address set: {hostname} now resolves to other addressesadmitted {admitted}; now {current}submit the task again, so it is admitted with the addresses the name resolves to nowrefused, exit 1, HTTP 403tests/agent/evidence-target-failures.mjs::a_request_after_the_target_moved_is_withheld
evidence-ledger-unlabelledfiling a withheld edge of a browser-evidence runthe browser-evidence ledger needs the run label that names its recordings directory, and the session has none; a defect of the callerlabel "{label}"report the caller: a browser-evidence session is started with its run labelunknown, exit 1, HTTP 500tests/agent/evidence-target-failures.mjs::a_ledger_without_its_run_is_refused
evidence-tool-withheldrunning {tool} in a browser-evidence runpolicy_withheld:{category}:{reason}tool {tool}; the withheld edge is in the run ledgercontinue with non-interactive observation; the policy admits only the controls the evidence declaration namesrefused, exit 1, HTTP 403tests/agent/evidence-target-failures.mjs::an_interactive_tool_the_policy_withholds_is_named

vision#

17 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
screenshot-capture-failedtaking the screenshot of the page at {url}the page refused a css-scaled and a plain PNG capture alike: it was closed or navigated away while it was captured, or the browser endedcss-scaled capture: {scaled}; plain capture: {plain}run the step again on an open page; when the browser ended, the run's browser log names whyunknown, exit 1, HTTP 500tests/vision/screenshot-failures.mjs::a_page_that_refuses_both_captures_is_named
screenshot-cdp-failedtaking the screenshot of the page at {url}the DevTools connection refused Page.captureScreenshot: the target was closed, or the connection droppedPage.captureScreenshot threw: {problem}reconnect to the page and ask again; `weles doctor` shows whether the browser answersunknown, exit 1, HTTP 500tests/vision/screenshot-failures.mjs::a_capture_the_devtools_connection_refuses_is_named
screenshot-cdp-emptytaking the screenshot of the page at {url}Page.captureScreenshot answered without image data: the page has no surface to capture (a minimised or zero-sized window)the answer holds: {members}give the window a size (launch it headed with a viewport, or headless) and ask againunknown, exit 1, HTTP 500tests/vision/screenshot-failures.mjs::a_capture_answered_without_data_is_named
screenshot-page-unsupportedtaking the screenshot of the page handed to the questionthe object handed as the page offers neither screenshot() nor send(), so there is no way to capture itthe object offers: {members}hand the question a Playwright page or a DevTools page connection (CDPConnection) of the sessionconfig, exit 1, HTTP 503tests/vision/screenshot-failures.mjs::a_page_that_cannot_be_captured_is_named
screenshot-not-pngreading the size of the screenshot of the page for the click target "{description}"the screenshot the page gave is not a PNG datastream, so its width and height cannot be read from its header{bytes} bytes, beginning {head}capture the page as png (its screenshot() with type png), then ask againunknown, exit 1, HTTP 500tests/vision/screenshot-failures.mjs::a_screenshot_that_is_no_png_is_named
question-record-unwritablerecording the screenshot of the {tier} question in {directory}the vision folder refused the screenshot ({errno}): it is not writable by the worker user, or its disk is full{path}: {problem}; the model was not askedgive the worker's user write access to {directory} (WELES_VISION_DIR, else the run's vision folder under WELES_RECORDINGS_ROOT) and free space on its disk, then ask againconfig, exit 1, HTTP 503tests/vision/question-failures.mjs::a_vision_folder_that_refuses_the_screenshot_is_named
question-log-unwrittenrecording the answer to the {tier} question in {directory}the vision folder refused the question's record ({errno}): it is not writable by the worker user, or its disk is full; the question went on without it{path}: {problem}give the worker's user write access to {directory} (WELES_VISION_DIR, else the run's vision folder under WELES_RECORDINGS_ROOT) and free space on its disk, then ask againconfig, exit 1, HTTP 503tests/vision/question-failures.mjs::a_vision_folder_that_refuses_the_record_is_named
question-arguments-not-jsonreading the {function} answer to the {tier} question "{question}"the arguments the model gave {function} are not JSON, so the answer cannot be read{bytes} characters; the parser said: {problem}ask again; a model that keeps answering so needs an alternative chosen with `stado capabilities select inference --order ...`; the question's record in the run's vision folder keeps the raw answerunknown, exit 1, HTTP 500tests/vision/question-failures.mjs::an_answer_whose_arguments_are_not_json_is_named
question-shows-absentreading the {function} answer to the {tier} question "{question}"the answer carries no boolean shows, so it says neither yes nor noarguments: {members}; shows is {kind}ask again; a model that keeps answering so needs an alternative chosen with `stado capabilities select inference --order ...`unknown, exit 1, HTTP 500tests/vision/question-failures.mjs::a_yes_or_no_answer_without_shows_is_named
question-kind-undeclaredreading the {function} answer to the {tier} question "{question}"the answer names {kind} as the kind of page, which is none of the kinds the question declareskind {kind}; declared: {kinds}ask again; a model that keeps answering so needs an alternative chosen with `stado capabilities select inference --order ...`unknown, exit 1, HTTP 500tests/vision/question-failures.mjs::a_page_kind_that_is_not_declared_is_named
question-controls-not-listreading the {function} answer to the {tier} question "{question}"the controls answer carries no list of controls, so none can be matched to the click targetarguments: {members}; controls is {kind}ask again; a model that keeps answering so needs an alternative chosen with `stado capabilities select inference --order ...`unknown, exit 1, HTTP 500tests/vision/question-failures.mjs::a_controls_answer_without_a_list_is_named
question-point-not-numericreading the point to click for "{description}"the {source} carries no numeric x and y, so there is no point to clickmembers: {members}; x is {x}, y is {y}ask again; a model that keeps answering so needs an alternative chosen with `stado capabilities select inference --order ...`unknown, exit 1, HTTP 500tests/vision/question-failures.mjs::a_point_without_numbers_is_named
question-pick-not-jsonreading which of {count} listed controls is "{description}"the arguments the model gave {function} are not JSON, so the chosen control cannot be read{bytes} characters; the parser said: {problem}ask again; a model that keeps answering so needs an alternative chosen with `stado capabilities select inference --order ...`unknown, exit 1, HTTP 500tests/vision/question-failures.mjs::a_control_choice_that_is_not_json_is_named
question-label-not-offeredreading which of {count} listed controls is "{description}"the model picked {label}, a label none of the listed controls carries, though the choice admits only theirspicked {label}; offered {offered}ask again; a model that keeps answering so needs an alternative chosen with `stado capabilities select inference --order ...`unknown, exit 1, HTTP 500tests/vision/question-failures.mjs::a_control_choice_of_another_label_is_named
question-refused-untranscribedasking the {tier} question "{question}"the model declined to answer about the screenshot, and declined to transcribe it too, so the question was asked of neitherabout the screenshot: {reason}; asked to transcribe it: {transcription}ask a question the page itself answers, or one a model of another alternative takes (`stado capabilities select inference --order ...`)refused, exit 1, HTTP 403tests/vision/question-failures.mjs::a_question_refused_and_left_untranscribed_is_named
question-refused-twiceasking the {tier} question "{question}"the model declined to answer about the screenshot, and declined again when asked of its transcriptionabout the screenshot: {reason}; about the transcription: {again}ask a question the page itself answers, or one a model of another alternative takes (`stado capabilities select inference --order ...`)refused, exit 1, HTTP 403tests/vision/question-failures.mjs::a_question_refused_of_both_is_named
question-click-target-refusedfinding the click target "{description}" on a {width}x{height} screenshotthe model declined both ways of finding it: the point asked of the screenshot and the list of its controlstier_0_bare: {bare}; tier_1_decompose: {list}name the control by a selector or its visible text instead, or describe it as the page labels itrefused, exit 1, HTTP 403tests/vision/question-failures.mjs::a_click_target_refused_by_both_tiers_is_named

Executor#

How an operator command fails to reach the managed Weles executor through Stado or WELES_WORKER_API_BASE. Every command that talks to the executor meets these.

25 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
stado-unavailablerunning `stado {command}`the Stado program cannot be run: WELES_STADO_BIN and STADO_BIN name none that runs, no stado is on PATH, and none is where its installer places it{answer}install Stado (its installer places it in $HOME/.stado/bin/stado, or in STADO_BIN_DIR when that is set), put it on PATH, or name the program with WELES_STADO_BINconfig, exit 1, HTTP 503tests/sign-in/executor.mjs::login_on_a_host_without_stado_names_where_it_looked
stado-refusedrunning `stado {command}`Stado ran and refused the request; its own words below name what it refused and whystado exited {status}: {answer}run the same stado command by hand, correct what it names (a target the registry does not hold, a credential it does not have), then run againrefused, exit 1, HTTP 403tests/sign-in/executor.mjs::login_whose_capabilities_stado_refuses_quotes_stado
stado-answer-not-jsonreading what `stado {command}` answeredStado exited 0 but did not print the JSON document --json promises: an older Stado, or something writing to its standard output{answer}upgrade Stado to the version this Weles release names as minimum_stado_version, then run againconfig, exit 1, HTTP 503tests/sign-in/executor.mjs::login_through_a_stado_that_prints_no_json_names_it
stado-locator-form-invalidreading the command line of src/_shared/linking/stado.cjsthe Stado locator a release script runs takes one form, `program`, which prints the Stado program every module of Weles runsgiven: {given}run node src/_shared/linking/stado.cjs programrefused, exit 2, HTTP 403tests/release/stado-locator.mjs::the_locator_refuses_a_form_it_does_not_take
executor-route-unresolvedfinding the Weles executorWELES_WORKER_API_BASE is not set and Stado places no weles-admission service this shell can connect to{answer}set WELES_WORKER_API_BASE and WELES_WORKER_TOKEN to the executor's address and bearer, or run where `stado service directory connect weles-admission --consumer operator` answers a urlnot_found, exit 1, HTTP 404tests/sign-in/executor.mjs::login_reading_a_run_where_stado_places_no_executor
host-unnamednaming this host's registry target`stado registry self --name-only` printed no nameit printed nothingenrol this host in the Stado registry, then ask againconfig, exit 1, HTTP 503tests/skarbiec/failures.mjs::a_stado_that_names_no_host_is_refused
variable-missingreading {name}{name} is not set, or set empty{name}: not setset {name}; for the executor, WELES_WORKER_TOKEN is the token field of the item playing the echo-weles-api role (stado credentials get --role echo-weles-api --field token)config, exit 1, HTTP 503tests/sign-in/executor.mjs::login_with_an_executor_address_and_no_token_names_the_variable
variable-invalidreading {name}{name} holds whitespace around it or a control character, so it cannot be sent in a header or a URL{name} holds {length} characters, some of them whitespace or control charactersset {name} to the value alone, with no newline or space around itconfig, exit 1, HTTP 503tests/sign-in/executor.mjs::login_with_a_token_holding_a_newline_names_the_variable
endpoint-invalidreading {name}{name} is not of the form it must have: an address that does not parse or carries credentials, a query or a fragment, or an id that is not a UUID{name}: {value}; {answer}set {name} to the base address alone (such as https://<host>), or to the organization UUID for WISENT_ORGANIZATION_IDconfig, exit 1, HTTP 503tests/sign-in/executor.mjs::login_with_an_executor_address_that_is_not_a_url_names_it
endpoint-insecurereading {name}it names a plain-HTTP address on another machine, over which the bearer would travel readable{name}: {value}use https:// for a remote executor; plain http:// is accepted only for a loopback addressrefused, exit 1, HTTP 403tests/sign-in/executor.mjs::login_with_a_remote_plain_http_executor_is_refused
executor-unreachable{operation} at {endpoint}no HTTP answer came back: the host has no DNS answer, nothing listens on that port, or the connection was cut{answer}check the executor runs there (stado service status com.wisent.weles) and that the address is the one Stado places it at, then run againinfra_down, exit 69, HTTP 503, retryabletests/sign-in/executor.mjs::login_reading_a_run_from_a_closed_port_names_the_address
executor-unauthorized{operation} at {endpoint}the executor did not admit the bearer: it is another deployment's, or the item was rotated after it was readHTTP {status}: {answer}read the bearer again with `stado credentials get --role echo-weles-api --field token` (or correct WELES_WORKER_TOKEN) and run againauth, exit 1, HTTP 401tests/sign-in/executor.mjs::login_reading_a_run_with_a_wrong_bearer_is_refused_by_the_executor
executor-refused{operation} at {endpoint}the executor understood the request and refused it; its own words below say whyHTTP {status}: {answer}correct what the executor names and run againrefused, exit 1, HTTP 403tests/sign-in/executor.mjs::login_reading_a_run_id_the_executor_refuses_quotes_it
executor-not-found{operation} at {endpoint}the executor holds nothing at that address: the run id belongs to another executor, the run left no result yet, or its record was removedHTTP {status}: {answer}check the run id against `weles runs list`, and read it from the executor that started itnot_found, exit 1, HTTP 404tests/sign-in/executor.mjs::login_reading_a_run_the_executor_never_had_is_not_found
executor-failed{operation} at {endpoint}the executor, or the forward in front of it, failed while answeringHTTP {status}: {answer}read the executor's log (stado service logs com.wisent.weles) for the failure it names, then run againinfra_down, exit 69, HTTP 503, retryabletests/sign-in/executor.mjs::login_reading_a_run_through_a_failing_forward_quotes_its_answer
executor-answer-not-json{operation} at {endpoint}what answered is not the executor: a forward, proxy or other service answered in plain text or HTML because it could not reach the executor{answer}check the address names the executor and that the Stado forward to it is up (stado service directory connect weles-admission), then run againinfra_down, exit 69, HTTP 503, retryabletests/sign-in/executor.mjs::login_reading_a_run_through_a_page_that_is_not_the_executor_names_it
run-not-startedstarting {action} on the executorthe executor answered without starting a detached run: it refused the action or its parametersthe executor answered: {answer}read the executor's answer above; `weles runs list` shows what it runs nowrefused, exit 1, HTTP 403tests/sign-in/failures.mjs::login_whose_run_the_executor_does_not_start_quotes_it
run-result-unreadablereading the result of run {run}the run's run-result.json carries no status: it was written by another program, or is not a run result{answer}read the run's files with `weles runs show {run}` to see what it wroterefused, exit 1, HTTP 403tests/sign-in/failures.mjs::login_reading_a_result_without_a_status_names_it
run-unrelated{operation}: reading the {action} run the executor answeredthe executor answered a run that is not a {action} run with its id, state and login binding: the run id names a run of another action, or the executor runs an older Weles release that records no bindinganswered: {answer}check the run id is the one the start answered; when it is, compare `weles version` with the release `stado service status com.wisent.weles` names and move the executor onto it with `stado service update`; a missing binding is never acceptedconfig, exit 1, HTTP 503tests/security/failures.mjs::security_reading_a_run_of_another_action_names_it
run-rebound{operation}: binding the {action} run to its requestthe executor answered a run bound to another request than the one asked: another login, run id, organization or account than requested, so its outcome would describe another accountasked {asked}; the executor answered {answered}inspect the run with `weles runs show <run-id>` and the executor's release (`weles worker version`) before starting another; do not accept a run bound to another accountconfig, exit 1, HTTP 503tests/security/failures.mjs::security_start_answered_for_another_role_is_refused
submit-action-invalidstarting a follow-up runthe action {action} is not an action name: lowercase letters, digits and _, beginning with a letteraction: {action}name the action as the run that asks for it declares it (`weles errors show trajectories` lists the trajectories)refused, exit 1, HTTP 403tests/runs/submitting/submit-failures.mjs::a_follow_up_of_no_action_name_is_refused
submit-account-invalidstarting the follow-up run {action} on this hostthe account item {item} is not a Skarbiec item id: a letter or digit, then letters, digits, ., _, : and -accountItem: {item}pass the exact id of the account item the run acts for, as its record names itrefused, exit 1, HTTP 403tests/runs/submitting/submit-failures.mjs::a_follow_up_for_an_item_of_no_id_is_refused
submit-params-invalidstarting the follow-up run {action} on this hostparams is {kind}, where a run takes one object of named parametersparams: {params}pass the parameters as one object of named values, as the action reads themrefused, exit 1, HTTP 403tests/runs/submitting/submit-failures.mjs::a_follow_up_with_params_of_no_object_is_refused
submit-api-unnamedstarting the follow-up run {action} on this hostneither WELES_WORKER_API_BASE nor WELES_API_PORT is set in this process, so it names no Weles API to start the run onWELES_WORKER_API_BASE: not set; WELES_API_PORT: not setrun this inside a trajectory the Weles API started (it states WELES_API_PORT), or set WELES_WORKER_API_BASE to the API off this hostconfig, exit 1, HTTP 503tests/runs/submitting/submit-failures.mjs::a_follow_up_outside_a_weles_api_names_the_settings
submit-token-unsetstarting the follow-up run {action} on this hostnone of WELES_API_TOKEN, WELES_CONSOLE_API_TOKEN or WELES_WORKER_TOKEN is set in this process, so the API would refuse the runthe API at {endpoint}; no bearerrun this inside a trajectory the Weles API started (it states WELES_API_TOKEN), or set WELES_WORKER_TOKEN from `stado credentials get --role echo-weles-api --field token`config, exit 1, HTTP 503tests/runs/submitting/submit-failures.mjs::a_follow_up_without_a_bearer_names_the_settings

runs#

15 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
action-missingreading the weles runs command lineweles runs needs an action, and none was namedthe actions weles runs takes: {verbs}run `weles runs <action>` with one of {verbs}; `weles runs --help` describes eachrefused, exit 2, HTTP 403tests/runs/failures.mjs::runs_without_an_action_names_the_actions
action-unknownreading the weles runs command lineunknown runs action: {action} is not an action weles runs takesaction: {action}; weles runs takes {verbs}name one of {verbs}refused, exit 2, HTTP 403tests/runs/failures.mjs::runs_refuses_an_action_it_does_not_take
options-unknownreading the weles runs {action} command lineit holds a word or option runs {action} does not takenot taken: {given}; runs {action} takes {taken}leave out {given}; `weles runs --help` lists what each action takesrefused, exit 2, HTTP 403tests/runs/failures.mjs::runs_refuses_an_option_its_action_does_not_take
run-id-missingreading the run runs {verb} acts onruns {verb} requires <run-id>, and none was givenweles runs {verb} with no run idgive the run id `weles runs list` prints first on each line: weles runs {verb} <run-id>refused, exit 2, HTTP 403tests/runs/failures.mjs::runs_show_without_a_run_id_is_refused
run-id-invalidreading the run runs {verb} acts ona run id is a letter or digit followed by letters, digits, _ and -, since it names the run result file, and this is not onerun id: {run}give the run id exactly as `weles runs list` or the run that started it printed itrefused, exit 2, HTTP 400tests/runs/failures.mjs::runs_refuses_a_run_id_that_cannot_name_a_run
answer-missingreading what the person did for runs answerruns answer requires exactly one of --ready, --approved or --not-received; ending the wait is weles runs cancel <run-id> --detail <who and why>answers given: {given}give one of --ready (the phone is in hand), --approved (the prompt was approved) or --not-received (it never arrived)refused, exit 2, HTTP 403tests/runs/failures.mjs::runs_answer_without_exactly_one_answer_is_refused
detail-missingreading --detail for runs {verb}runs cancel requires --detail <who cancels it and why>, which the run record keeps, and runs answer takes --detail only with its text--detail: {value}give --detail "<one sentence>": who cancels the run and why, or what the person sawrefused, exit 2, HTTP 400tests/runs/failures.mjs::runs_cancel_without_detail_is_refused
body-not-jsonreading the request to {verb} run {run}its body is not JSON, so the worker cannot read the answer or detail it carries{method} {path}: {bytes} bytes; parser: {answer}send a JSON object, such as {"detail": "<who and why>"}; `weles runs {verb}` sends onerefused, exit 2, HTTP 400tests/runs/failures.mjs::runs_cancel_with_a_body_that_is_not_json_is_refused
answer-invalidreading what the person did for run {run}answer is not one the worker takes; ending the wait is POST /runs/{run}/cancelanswer: {value}; the worker takes {answers}send answer as one of {answers}, as `weles runs answer` doesrefused, exit 2, HTTP 400tests/runs/failures.mjs::runs_answer_the_worker_does_not_take_is_refused
run-not-foundfinding run {run} to {verb}the worker holds no record of it and runs no child for it: it belongs to another worker, or it never startedrun_not_found: no record and no live child for {run} on this workercheck the id against `weles runs list` and read it from the worker that started itnot_found, exit 1, HTTP 404tests/runs/failures.mjs::runs_show_of_a_run_the_worker_never_had_is_not_found
run-finishedreaching run {run} to {verb}the run has finished, so nothing is left to {verb}run_not_running_here: the run finished at {completed}; there is nothing to {verb}read what it left with `weles runs show {run}`, and start a new run if its work is still neededrefused, exit 1, HTTP 409tests/runs/failures.mjs::runs_cancel_of_a_finished_run_names_when_it_finished
run-orphanedreaching run {run} to {verb}the server that ran it has stopped: its record still says {status}, and this server has no child for itrun_not_running_here: the run is recorded as {status} but this server has no child for itstart the run again if its work is still needed; `weles runs show {run}` prints the record it leftrefused, exit 1, HTTP 409tests/runs/failures.mjs::runs_cancel_of_a_run_whose_server_stopped_names_its_status
run-not-waitinganswering run {run}the run waits for no answer from a personrun_not_waiting: it stands at {stage}answer only a run `weles runs list` shows as WAITS FOR YOU; end this one with weles runs cancel {run} --detail <who and why>refused, exit 1, HTTP 409tests/runs/failures.mjs::runs_answer_to_a_run_that_waits_on_nobody_names_its_stage
run-record-unreadablereading run {run}'s record on the workerits result file {file} in the worker's detached-runs directory cannot be read as a JSON document: a write was cut off, its permissions changed, or another program wrote it{answer}on the worker's host, move ~/.stado/weles-detached-runs/{file} aside; the run's evidence stays under its recordings, and a later run of that id writes a new recordconfig, exit 1, HTTP 500tests/runs/failures.mjs::runs_show_of_a_record_that_is_not_json_names_the_file
answer-unexpected{operation} at {endpoint}the worker answered JSON of another shape than the runs it lists, shows, answers and cancels: it runs another Weles release than this CLI{answer}compare `weles version` with `weles worker version` and install the same Weles release on bothconfig, exit 1, HTTP 503tests/runs/failures.mjs::runs_list_through_an_answer_without_a_run_list_names_it

security#

6 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
options-unknownreading the weles security command lineit holds a word or option security does not take: security accepts --provider with --login-role, or --run; it cannot enable, disable or enrol 2FAnot taken: {given}leave out {given}: weles security --provider google --login-role <skarbiec-role> [--json], or weles security --run <run-id> [--json]refused, exit 2, HTTP 403tests/security/failures.mjs::security_refuses_an_option_it_does_not_take
selector-invalidchoosing what weles security readsprovide exactly one of --login-role <skarbiec-role> or --run <run-id>, each with a value that is not blankgiven: {given}give --login-role with the Skarbiec role the Google login plays to start a check, or --run with the run id a start answered to read it backrefused, exit 2, HTTP 403tests/security/failures.mjs::security_without_exactly_one_selector_is_refused
provider-unsupportedchoosing the identity provider whose account is readsecurity needs --provider naming the identity provider whose account it reads; Weles reads {providers}--provider: {provider}give --provider {providers}refused, exit 2, HTTP 403tests/security/failures.mjs::security_refuses_a_provider_it_cannot_read
run-takes-no-start-optionsreading the weles security --run command line--run reads a started run back and takes no --providergiven with --run: {given}leave out {given}: weles security --run <run-id> [--json]refused, exit 2, HTTP 403tests/security/failures.mjs::security_reading_a_run_refuses_a_provider
run-id-invalidreading the weles security --run command line--run {run} is no run id: a run id starts with a letter or digit and holds only letters, digits, _ and -, as the start answered it--run {run}; nothing was asked of the executorgive --run with the run id `weles security --provider google --login-role <role>` answered, or one `weles runs list` printsrefused, exit 2, HTTP 403tests/security/failures.mjs::security_refuses_a_run_id_that_is_none
observation-invalid{operation}: reading the 2FA observation of run {run}the run recorded a result that is not a weles.account-security.v1 observation of the login it was bound to: a field is missing or of another type, it names another login item, or ok disagrees with two_factor_enabledresult: {answer}compare `weles version` with the release `stado service status com.wisent.weles` names and move the executor onto it with `stado service update`, then submit a new check; an invalid observation is never read as a verdictconfig, exit 1, HTTP 503tests/security/failures.mjs::security_reading_an_invalid_observation_names_it

password#

7 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
options-unknownreading the weles password command lineit holds a word or option password does not take: password accepts --provider with --login-role or --login-item, --organization and --account, or --run, and --jsonnot taken: {given}leave out {given}: weles password --provider google --login-role <skarbiec-role>|--login-item <skarbiec-item> --organization <skrzynka-organization> --account <mailbox-email> [--json], or weles password --run <run-id> [--json]refused, exit 2, HTTP 403tests/security/passwords/password-failures.mjs::password_refuses_an_option_it_does_not_take
selector-invalidchoosing the login weles password signs in withprovide exactly one of --login-role <skarbiec-role>, --login-item <skarbiec-item> or --run <run-id>, each with a value that is not blankgiven: {given}give --login-role with the role the Google login plays in Skarbiec, --login-item with the exact login item, or --run with the run id a start answeredrefused, exit 2, HTTP 403tests/security/passwords/password-failures.mjs::password_without_exactly_one_selector_is_refused
organization-missingreading --organization--organization <id> names the Skrzynka organization the mailbox is declared in; none is assumed--organization: {value}give --organization with the Skrzynka organization the mailbox is declared in; `skrzynka --organization <id> mailbox list` shows the mailboxes an organization declaresrefused, exit 2, HTTP 403tests/security/passwords/password-failures.mjs::password_without_an_organization_is_refused
account-missingreading --account--account must name the Gmail account the mailbox belongs to; it is compared with the login before any browser opens, and none is inferred from the login--account: {value}give --account <mailbox-email>, the address of the mailboxrefused, exit 2, HTTP 403tests/security/passwords/password-failures.mjs::password_without_an_account_is_refused
provider-unsupportedchoosing the identity provider that issues the app passwordpassword needs --provider naming the identity provider that issues it; Weles issues through {providers}--provider: {provider}give --provider {providers}refused, exit 2, HTTP 403tests/security/passwords/password-failures.mjs::password_refuses_a_provider_it_cannot_issue_through
run-takes-no-start-optionsreading the weles password --run command line--run reads a started run back and takes no --organization, --provider or --accountgiven with --run: {given}leave out {given}: weles password --run <run-id> [--json]refused, exit 2, HTTP 403tests/security/passwords/password-failures.mjs::password_reading_a_run_refuses_start_options
run-id-invalidreading the weles password --run command line--run {run} is no run id: a run id starts with a letter or digit and holds only letters, digits, _ and -, as the start answered it--run {run}; nothing was asked of the executorgive --run with the run id `weles password --provider google --login-role <role> ...` answered, or one `weles runs list` printsrefused, exit 2, HTTP 403tests/security/passwords/password-failures.mjs::password_refuses_a_run_id_that_is_none

oauth-callback#

8 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
options-unknownreading the weles oauth-callback command lineit holds a word or option oauth-callback does not take: oauth-callback accepts --provider with --login-role or --login-item, --client-role or --client-item and --callback, or --run, and --jsonnot taken: {given}leave out {given}: weles oauth-callback --provider google --login-role <skarbiec-role>|--login-item <skarbiec-item> --client-role <skarbiec-role>|--client-item <skarbiec-item> --callback <https-url> [--json], or weles oauth-callback --run <run-id> [--json]refused, exit 2, HTTP 403tests/security/oauth/oauth-callback-failures.mjs::oauth_callback_refuses_an_option_it_does_not_take
value-blankreading --{option}--{option} needs a value that is not blank--{option}: {value}give --{option} its value, or leave the option outrefused, exit 2, HTTP 403tests/security/oauth/oauth-callback-failures.mjs::oauth_callback_refuses_a_blank_value
run-takes-no-start-optionsreading the weles oauth-callback --run command line--run reads a started run back and takes no other option but --jsongiven with --run: {given}leave out {given}: weles oauth-callback --run <run-id> [--json]refused, exit 2, HTTP 403tests/security/oauth/oauth-callback-failures.mjs::oauth_callback_reading_a_run_refuses_start_options
run-id-invalidreading the weles oauth-callback --run command line--run {run} is no run id: a run id starts with a letter or digit and holds only letters, digits, _ and -, as the start answered it--run {run}; nothing was asked of the executorgive --run with the run id a start answered, or one `weles runs list` printsrefused, exit 2, HTTP 403tests/security/oauth/oauth-callback-failures.mjs::oauth_callback_refuses_a_run_id_that_is_none
provider-unsupportedchoosing whose OAuth client weles oauth-callback editsoauth-callback needs --provider naming whose OAuth client it edits; Weles edits {providers}--provider: {provider}give --provider {providers}refused, exit 2, HTTP 403tests/security/oauth/oauth-callback-failures.mjs::oauth_callback_refuses_a_provider_it_does_not_edit
login-selector-invalidchoosing the login weles oauth-callback signs in withprovide exactly one of --login-role <skarbiec-role> or --login-item <skarbiec-item>given: {given}give --login-role with the role the owner login plays in Skarbiec, or --login-item with the exact login itemrefused, exit 2, HTTP 403tests/security/oauth/oauth-callback-failures.mjs::oauth_callback_without_exactly_one_login_is_refused
client-selector-invalidchoosing the OAuth client weles oauth-callback editsprovide exactly one of --client-role <skarbiec-role> or --client-item <skarbiec-item>given: {given}give --client-role with the role the OAuth client item plays in Skarbiec, or --client-item with the exact item; the client secret is never asked forrefused, exit 2, HTTP 403tests/security/oauth/oauth-callback-failures.mjs::oauth_callback_without_exactly_one_client_is_refused
callback-invalidreading --callback--callback must be the https URL, with a host, the provider must accept--callback: {callback}give --callback the sign-in server's https callback address, e.g. https://<host>/auth/v1/callbackrefused, exit 2, HTTP 403tests/security/oauth/oauth-callback-failures.mjs::oauth_callback_refuses_a_callback_that_is_not_https

Sign-in#

How weles login --provider apple fails, from the command line to the run's record.

16 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
options-unknownreading the weles {command} command lineit holds a word or option {command} does not take: {command} either starts a run with {start} or reads one back with {read}not taken: {given}run `weles {command} --help` for the two forms and give one of themrefused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_an_option_it_does_not_take
provider-unsupportedchoosing the provider weles {command} goes through--provider is missing or names a provider Weles has no {command} for--provider: {provider}; providers Weles takes: {providers}give --provider {providers}refused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_a_provider_it_cannot_sign_in_to
option-value-missingreading --{option} of weles {command}--{option} is required and was given no value--{option}: {value}give --{option} <{meaning}>refused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_a_missing_execution_host
account-role-invalidreading --account-role of weles {command}a Skarbiec role is lowercase letters, digits and hyphens, starting with a letter or digit, at most 127 characters--account-role: {value}give the role the Apple account plays in Skarbiec (the item tagged stado:role:<role>), or leave it out for {standard}refused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_an_account_role_that_is_not_a_role
confirmation-mismatchauthorizing one run of weles {command}the operator's confirmation is not the exact phrase of this command, so no authorization is issued--confirm: {value}give --confirm "{phrase}" exactly, in capitalsrefused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_a_confirmation_that_is_not_the_phrase
execution-host-invalidreading --{option} of weles {command}a Stado host name is letters, digits, ., _ and -, starting with a letter or digit, at most 253 characters--{option}: {value}give the registry target, as `stado registry host list` names itrefused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_an_execution_host_that_is_not_a_host_name
expiry-invalidreading --expires-in-minutes of weles {command}the lifetime of the one-use capabilities is a positive whole number of minutes--expires-in-minutes: {value}give --expires-in-minutes <n>, the minutes the run may take, such as 15refused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_an_expiry_that_is_not_whole_minutes
run-id-missingreading an authorized Apple run back--run names no run id--run: no valuegive --run <run-id>, the run the start answeredrefused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_run_without_an_id
run-id-invalidreading the weles {command} --run command line--run {run} is no run id: a run id starts with a letter or digit and holds only letters, digits, _ and -, as the start answered it`weles {command} --run {run}`; nothing was asked of the executorrun `weles {command} --run <run-id>` with the run id the start answered, or one `weles runs list` printsrefused, exit 2, HTTP 403tests/sign-in/failures.mjs::login_refuses_a_run_id_that_is_none
install-incompleteloading the Apple capability issuer {module}the installed Weles lacks the module that asks Stado for the capabilities: the install is incomplete or was built without src/auth{answer}reinstall the Weles release through Stado (its payload carries src/auth), then run againconfig, exit 1, HTTP 503tests/sign-in/failures.mjs::login_from_an_install_without_the_issuer_names_the_module
capabilities-not-issuedissuing the Apple capabilities on {host}Stado answered, but not with capabilities issued for that host: it issued them for another target, or reported a status other than issued{answer}run `stado identity issue --provider apple --target {host} ...` by hand to see what it answers, and correct the target or Stado's identity configurationrefused, exit 1, HTTP 403tests/sign-in/failures.mjs::login_whose_capabilities_name_another_host_is_refused
challenge-not-confirmedrelaying the Apple two-factor challenge (stado {command})Stado answered without confirming the challenge as {expected} with its holder, user and destination{answer}run the same stado identity relay command by hand on the execution host, and correct the session or identity it namesrefused, exit 1, HTTP 403tests/sign-in/failures.mjs::relay_whose_stado_answer_lacks_the_holder_is_refused
relay-input-missingrelaying the Apple two-factor challengethe Apple trajectory runs without {missing}: it was started without the params weles login, agreement and certificate give every runidentity: {identity}; authorization id: {authorization}start the run with `weles login`, `weles agreement` or `weles certificate`, which issue the authorization and name the account roleconfig, exit 1, HTTP 503tests/sign-in/failures.mjs::relay_without_an_authorization_id_is_refused
apple-no-trusted-devicewaiting for the Apple two-factor code of {account}Apple lists no trusted device for this Apple ID, so it notifies none, the account holder's Mac included: that Mac is not signed in to iCloud with this Apple ID, or Apple no longer trusts it; the code goes only to a trusted phone numberApple answered noTrustedDevices {flag}, {devices} trusted devices and {phones} trusted phone numbers; nothing was relayedsign in to iCloud with this Apple ID on the Mac Stado places the account holder on (System Settings, Apple Account), so Apple trusts it, then run again; `stado identity relay --provider apple --identity <role> --preflight` names that holderrefused, exit 1, HTTP 403tests/sign-in/failures.mjs::an_apple_id_with_no_trusted_device_is_named_before_the_relay
apple-codes-heldwaiting for the Apple two-factor code of {account}Apple holds back new codes for this Apple ID ({flag} is true), so no device is notified until Apple lifts itApple's second-factor state: {flags}wait until Apple lets codes be sent again, then run again once; every further attempt spends one of the few Apple allowsrate_limit, exit 69, HTTP 429, retryabletests/sign-in/failures.mjs::an_apple_id_whose_codes_are_held_is_named_before_the_relay
apple-device-silentrelaying the Apple two-factor code of {account}Stado's relay from the account holder's session confirmed no code: that session is not a device Apple notifies (signed in to iCloud with another Apple ID, or its notifications for it are off), it never showed the code, or Apple sent nonewhere Apple sent it: {delivery}; the relay: {relay}check that the Mac Stado places the account holder on is signed in to iCloud with this Apple ID and shows its sign-in notifications, then run again; `stado identity relay --provider apple --identity <role> --preflight` names that holderrefused, exit 1, HTTP 403tests/sign-in/failures.mjs::a_relay_that_confirms_no_code_names_where_apple_sent_it

certificate#

11 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
subject-invalidreading --subject of weles certificate--subject is the certificate request's distinguished name, and it does not start with /CN=--subject: {value}give --subject "/CN=<organization> Developer ID Application/O=<organization>/C=<country>"refused, exit 2, HTTP 403tests/certificate/failures.mjs::certificate_refuses_a_subject_without_a_common_name
path-not-absolutereading --{option} of weles certificate--{option} must be an absolute path on this machine--{option}: {value}give --{option} as a path starting at /refused, exit 2, HTTP 403tests/certificate/failures.mjs::certificate_refuses_a_relative_key_path
key-and-store-apartreading weles certificate --run--private-key and --store-host go together: both store the identity in the vault, neither leaves it in files--private-key: {key}; --store-host: {host}give both to keep the identity in the vault of the store host, or neither to write only the certificaterefused, exit 2, HTTP 403tests/certificate/failures.mjs::certificate_refuses_a_key_without_a_store_host
file-existswriting the {what} to {path}a file already stands there, and weles certificate never replaces a {what}: a key that is replaced signs nothing its certificate names{path} existsgive --{option} a path where nothing stands, or move the file there away yourself if it is no longer neededrefused, exit 1, HTTP 403tests/certificate/failures.mjs::certificate_refuses_to_replace_a_private_key
private-key-missingreading the private key {path}no file stands at --private-key: it is not the path the start wrote the key to, or the key was moved{path} does not existgive --private-key the path the start answered as private_key, on the machine that ran the startnot_found, exit 1, HTTP 404tests/certificate/failures.mjs::certificate_refuses_a_private_key_that_is_not_there
openssl-failedrunning openssl {operation}openssl is not on the PATH of weles, or it refused the input: a key path it cannot write, a key that does not match the certificateopenssl said: {answer}install openssl on this machine (it ships with macOS), and give paths in a directory this user can writeconfig, exit 1, HTTP 503tests/certificate/failures.mjs::certificate_without_openssl_names_it
certificate-countreading the certificate run {run} returnedthe run ended ok but its output holds not exactly one CERTIFICATE_BASE64 line: it is a run of another trajectory, or the trajectory stopped printing one{count} certificate linesread the run with `weles runs show {run}`, and give --run the run weles certificate startednot_found, exit 1, HTTP 404tests/certificate/failures.mjs::certificate_from_a_run_without_one_names_the_count
certificate-invalidreading the certificate run {run} returnedthe bytes the run returned are not a DER X.509 certificate, so nothing was writtenopenssl said: {answer}read the run with `weles runs show {run}`; start a new run with weles certificate when its output is damagedrefused, exit 1, HTTP 403tests/certificate/failures.mjs::certificate_that_is_not_x509_is_refused
receipt-invalidreading the Apple two-factor receipt run {run} returnedthe run returned more than one receipt, or one that is not JSON, or one that lacks source capability, provider_accepted true, a holder, a user and a destination{answer}read the run with `weles runs show {run}`; a run without a complete receipt was not authorized by its holder, so start a new onerefused, exit 1, HTTP 403tests/certificate/failures.mjs::certificate_with_a_receipt_that_is_not_json_is_refused
certificate-unwritablewriting the certificate to {path}the file cannot be created: its directory does not exist, or this user may not write therethe system said: {answer}give --certificate-out a path in a directory this user can writeconfig, exit 1, HTTP 503tests/certificate/failures.mjs::certificate_into_a_missing_directory_is_named
common-name-missingnaming the signing identity of the certificate run {run} returnedthe certificate names no common name, which is the identity codesign selects, so it cannot be kept as a signing identitysubject: {subject}start a new run with a --subject that begins with /CN=; the certificate was written, the vault was not changedrefused, exit 1, HTTP 403tests/certificate/failures.mjs::certificate_without_a_common_name_is_not_stored

worker#

68 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
action-missingreading the weles worker command lineweles worker needs an action, and none was namedthe actions weles worker takes: {verbs}run `weles worker <action>` with one of {verbs}; `weles --help` describes eachrefused, exit 2, HTTP 403tests/worker/failures.mjs::worker_without_an_action_names_the_actions
action-unknownreading the weles worker command lineunknown worker action: {action} is not an action weles worker takesaction: {action}; weles worker takes {verbs}name one of {verbs}refused, exit 2, HTTP 403tests/worker/failures.mjs::worker_refuses_an_action_it_does_not_take
options-unknownreading the weles worker {action} command lineit holds a word or option worker {action} does not take; every worker action takes only --jsonnot taken: {given}leave out {given}: weles worker {action} [--json]refused, exit 2, HTTP 403tests/worker/failures.mjs::worker_refuses_a_word_or_option_its_action_does_not_take
control-in-progressworker {action} of the task dispatcheranother worker control request is changing the dispatcher now, and the worker takes one at a time, since a recovery rewrites one durable queueworker_control_in_progress: a control request was still running when {action} arrivedwait until the other request answers (`weles worker status` shows the dispatcher it left), then run weles worker {action} againrate_limit, exit 69, HTTP 409, retryabletests/worker/failures.mjs::worker_control_while_another_runs_is_refused
dispatcher-busyworker {action}: recovering the task dispatchera task is running or being started, or the server is shutting down, and the dispatcher recovers its durable queue only while nothing runsworker_busy: dispatcher {dispatcher}wait until `weles worker status` shows active 0 and draining false, or end the run with `weles runs cancel <run-id> --detail <who and why>`, then run weles worker {action} againrate_limit, exit 69, HTTP 409, retryabletests/worker/failures.mjs::worker_restart_while_a_task_runs_is_refused
recovery-failedworker {action}: recovering the durable task queuethe worker could not read back the task state it persisted under ~/.stado/weles-detached-runs/public-tasks: an entry that is no task, a task or reservation file that is not JSON, or a directory it cannot read; admission stays paused until a recovery succeedsworker_recovery_failed: {detail}on the worker's host, move aside the entry the failure names under ~/.stado/weles-detached-runs/public-tasks, then run weles worker restartconfig, exit 1, HTTP 502tests/worker/failures.mjs::worker_restart_over_task_state_that_is_no_task_names_the_entry
dispatcher-not-runningworker {action} of the task dispatcherthe dispatcher does not run after it: starting a queued task failed (its failure names the task and why), or the server began shutting downworker_not_running_after_control_action: dispatcher {dispatcher}on the worker's host, move aside the task file the failure names under ~/.stado/weles-detached-runs/public-tasks, then run weles worker restartconfig, exit 1, HTTP 502tests/worker/failures.mjs::worker_start_over_a_queued_task_that_cannot_be_read_names_it
answer-unexpected{operation} at {endpoint}the endpoint answered JSON of another shape than a resident Weles worker reports: it runs another Weles release than this CLI, or it is not Weles{answer}compare `weles version` with the release `stado service status com.wisent.weles` names, and move the worker onto the same release with `stado service update`config, exit 1, HTTP 503tests/worker/failures.mjs::worker_status_through_an_answer_of_another_shape_names_it
process-replaced{operation} at {endpoint}the worker answered its control with another process than the one it reported before: the endpoint restarts the service itself, as the retired native worker did, instead of controlling the dispatcher in the process that answersprocess {before} before, {after} aftermove the worker onto the current Weles release with `stado service update`, whose /worker routes control the resident dispatcher, then read `weles worker status`config, exit 1, HTTP 503tests/worker/failures.mjs::worker_control_that_replaces_the_process_is_refused
launch-address-unsetreading the address the Weles service declaration assigns{name} is not set: Stado writes WELES_API_HOST and WELES_API_PORT into the unit, and this process was started outside it{name}: not setstart the API through its unit (`stado service ensure weles --host <this host> --reason <why>`), or set {name} to the address the declaration assignsconfig, exit 1, HTTP 503tests/worker/launching/launch-failures.mjs::a_launch_without_its_address_names_the_variable
launch-port-duplicatestarting the Weles API on port {port}another Weles API already serves that port; a second process would only stand byweles api port {port} is already served by {holder}, which answers /healthz as {source}the existing API was not stopped; retire the duplicate service declaration with `stado service retire`refused, exit 1, HTTP 403tests/worker/launching/launch-failures.mjs::a_launch_onto_a_port_a_weles_serves_is_refused
launch-port-foreignstarting the Weles API on port {port}a process that is not a Weles API holds the port, and standing by would leave the service reported active while every caller failsweles api port {port} is held by {holder}, which is not a Weles API: {detail}stop or re-place the holder, then start the unit with `stado service ensure weles --host <this host> --reason <why>`infra_down, exit 69, HTTP 503, retryabletests/worker/launching/launch-failures.mjs::a_launch_onto_a_port_another_program_holds_is_refused
launch-workload-unsetreading the workload Weles acquires its secrets asSKARBIEC_WORKLOAD_ID is not set: the service unit names the workload Skarbiec's registry knows Weles bySKARBIEC_WORKLOAD_ID: not setstart the API through its unit (`stado service ensure weles --host <this host> --reason <why>`), whose declaration sets itconfig, exit 1, HTTP 503tests/worker/launching/launch-failures.mjs::a_launch_without_its_workload_names_it
launch-release-incompletereading {what} of this releasethe release payload lacks it or holds it in another shape: it was built or unpacked incompletely{answer}install the release again with `stado product install weles --surface service`config, exit 1, HTTP 503tests/worker/launching/launch-failures.mjs::a_release_without_its_capability_routes_is_named
launch-step-refusedthe startup step {step}the program it runs could not start, or exited refusing; its own words name the dependency{answer}correct what the step's own words name, then start the unit again with `stado service ensure weles --host <this host> --reason <why>`infra_down, exit 69, HTTP 503, retryabletests/worker/launching/launch-failures.mjs::a_startup_step_that_refuses_is_quoted
launch-forward-unpublishedreading the address Stado published for {service}the forward marker is missing, unreadable or empty: the service directory has not published {service} on this host{marker}: {answer}let `stado service directory publish` write it, then start the unit againconfig, exit 1, HTTP 503tests/worker/launching/launch-failures.mjs::a_launch_without_the_object_api_forward_names_it
launch-answer-emptythe startup step {step}it succeeded and printed nothing where it promises {what}an empty answerrun the step by hand (`node src/_shared/vaulting/skarbiec-runtime.mjs <question>` for Skarbiec) and correct what Stado declaresconfig, exit 1, HTTP 503tests/worker/launching/launch-failures.mjs::a_startup_answer_that_is_empty_is_named
launch-refusal-unservableserving the refused startup on {host}:{port}the address the API would listen on cannot be bound while the startup is refused: another process took the port after the launcher checked it, or the host no longer holds that address{answer}find what holds {host}:{port} (`lsof -nP -iTCP:{port} -sTCP:LISTEN`), stop or re-place it, then let the unit start againinfra_down, exit 69, HTTP 503, retryabletests/worker/launching/launch-failures.mjs::a_refused_startup_whose_address_is_taken_is_named
api-bearer-rejectedauthenticating {method} {path}the request carries no Authorization bearer or x-api-key equal to this API's token: none was sent, it is another deployment's, or the item was rotated after it was reada request without the API tokensend the token of the item playing echo-weles-api as the bearer (`stado credentials get --role echo-weles-api --field token`)auth, exit 1, HTTP 401tests/api/failures.mjs::a_token_route_without_the_api_token_is_refused
api-token-unsetauthenticating {method} {path}this API was started without WELES_API_TOKEN, so no bearer can be admitted: it was run outside its unit, whose launcher acquires the tokenWELES_API_TOKEN: not setstart the API through its unit (`stado service ensure weles --host <this host> --reason <why>`), whose launcher acquires WELES_API_TOKENconfig, exit 1, HTTP 500tests/api/failures.mjs::an_api_started_without_its_token_names_it
api-route-unknownrouting {method} {path}no route of this Weles API answers that method at that address{method} {path}send the request to a route the API answers; https://weles.wisent.com/docs/errors lists themnot_found, exit 1, HTTP 404tests/api/failures.mjs::an_address_no_route_answers_is_named
api-route-failedanswering {method} {path}the route raised an error it declares no cause for, so nothing analysed why it failed: a defect of this Weles release{answer}run `weles errors show worker` for the causes the route declares, and report the observed error with the route and `weles worker version`, so the cause is declared where it is raisedunknown, exit 1, HTTP 500tests/api/failures.mjs::a_route_failing_with_an_undeclared_error_is_named
api-body-not-jsonreading the body of {method} {path}the body is not one JSON document, so the route cannot read what it is asked{bytes} bytes; parser: {answer}send the request as one JSON object (Content-Type: application/json), or no bodyrefused, exit 1, HTTP 400tests/api/failures.mjs::a_run_whose_body_is_not_json_is_refused
api-answer-unserializableanswering {method} {path}the answer could not be serialized, so it cannot be redacted: it holds a value JSON cannot carry (a BigInt, or an object that holds itself), and an answer is never sent unredacted; a defect of this releaseserializer: {answer}report it with `weles worker version` and the route; the request had no answer, and nothing it changed was undoneunknown, exit 1, HTTP 500tests/api/failures.mjs::an_answer_json_cannot_carry_is_named
api-field-missingreading {field} of {method} {path}{field} is required, and the body does not carry ita body without {field}send {field}: {expected}refused, exit 1, HTTP 400tests/api/records-failures.mjs::a_record_request_without_its_field_is_refused
api-field-invalidreading {field} of {method} {path}{field} is not {expected}{field}: {value}send {field} as {expected}refused, exit 1, HTTP 400tests/api/pages-failures.mjs::a_page_request_with_a_field_of_another_shape_is_refused
api-body-unreadreading the body of {method} {path}the connection ended with an error after {bytes} bytes of the body, so the route never had the whole request{bytes} bytes read; connection: {errno}: {answer}send the request again; a proxy between the caller and the worker that cuts bodies shows in its own loginfra_down, exit 69, HTTP 400, retryabletests/api/failures.mjs::a_body_cut_off_by_the_caller_is_named
diagnostics-run-id-invalidreading the run whose evidence GET /diagnostics namesa run id is a letter or digit followed by letters, digits, ., _ and -, since it names the run directory, and this is not onerun id: {run}give the run id exactly as `weles runs list` or the run that started it printed itrefused, exit 1, HTTP 400tests/api/failures.mjs::evidence_of_a_run_id_that_cannot_name_a_run_is_refused
diagnostics-wait-invalidreading which file of run {run} to answer, and whether to wait for itwait=terminal waits for the run outcome only, so it requires path=run-result.json; no other wait existswait: {wait}; path: {path}ask for path=run-result.json with wait=terminal, or leave wait outrefused, exit 1, HTTP 400tests/api/failures.mjs::a_wait_for_another_file_is_refused
diagnostics-not-foundreading the evidence manifest of run {run}this worker holds no evidence for that run: it ran on another worker, it has not written any yet, or its evidence was removedno evidence directory for run {run}check the run id against `weles runs list`, and ask the worker that ran itnot_found, exit 1, HTTP 404tests/api/failures.mjs::evidence_of_a_run_the_worker_never_had_is_not_found
diagnostics-file-not-foundreading {path} of run {run}the run's evidence holds no such file: it is not written yet, it names a path outside the run's evidence, or no path was givenpath: {path}name a file the run's manifest lists (GET /diagnostics/{run}), or wait for run-result.json with wait=terminalnot_found, exit 1, HTTP 404tests/api/failures.mjs::a_file_the_evidence_does_not_hold_is_not_found
evidence-roots-unreadablefinding the recordings of run {run}no readable recording root holds the run, and {count} root(s) where its recordings may live could not be read by the worker user, so the run cannot be called absentunreadable: {roots}give the worker's user read and search access to each root named (`ls -ld` on it shows its owner and mode), or move a root that no longer belongs to Weles aside, then ask againconfig, exit 1, HTTP 500tests/api/evidence-failures.mjs::evidence_under_a_root_the_worker_cannot_read_names_the_root
evidence-file-unexaminableexamining {path} of run {run}the file exists under the run's recordings but the worker user cannot examine it ({code}), so it is neither served nor reported absent{file}: {answer}give the worker's user read and search access to {file} and the directories above it (`ls -ld` shows each one's owner and mode), then ask againconfig, exit 1, HTTP 500tests/api/evidence-failures.mjs::evidence_file_the_worker_cannot_examine_names_it
evidence-result-unexaminableexamining the persisted outcome of run {run}the results directory or the run's result file cannot be examined by the worker user ({code}), so the outcome is neither served nor reported absent{file}: {answer}give the worker's user read and search access to {directory} (`ls -ld {directory}` shows its owner and mode), then ask againconfig, exit 1, HTTP 500tests/api/evidence-failures.mjs::an_outcome_the_worker_cannot_examine_names_the_file
evidence-result-vanishedwaiting for the outcome of run {run}the run's result file existed when the wait began and was removed before the run ended: something other than the worker deleted or moved itno {file} any more; the wait had read {reads} version(s) of itfind what removes files under {directory} (a cleanup job, another worker sharing the home); the run itself is still on `weles runs show {run}`config, exit 1, HTTP 500tests/api/evidence-failures.mjs::an_outcome_removed_during_the_wait_is_named
evidence-result-not-jsonreading the persisted outcome of run {run}the run's result file is not one JSON document: the worker writes it whole and replaces it in one rename, so it was truncated or written by something else{file} ({bytes} bytes) begins {head}; parser: {answer}move {file} aside and read the run with `weles runs show {run}`; the run's recordings under GET /diagnostics/{run} still hold what it didconfig, exit 1, HTTP 500tests/api/evidence-failures.mjs::an_outcome_that_is_not_json_is_named
evidence-result-invalidreading the persisted outcome of run {run}the run's result is neither running (status running, ok null) nor ended (a status other than running and ok true or false), so whether the run ended cannot be read from it{file}: status {status}, ok {ok}compare `weles worker version` with the release that wrote {file}; move the file aside if another program wrote it, and read the run with `weles runs show {run}`config, exit 1, HTTP 500tests/api/evidence-failures.mjs::an_outcome_neither_running_nor_ended_is_named
evidence-results-directory-gonewaiting for the outcome of run {run}the directory the worker persists run outcomes in was moved or removed while the wait watched it, so the run's outcome can no longer arrive there{directory} renamed or removed; the run's file was {file}restore {directory} (the worker recreates it with its next run) and stop whatever moves it; ask again once `weles runs show {run}` shows the run endedconfig, exit 1, HTTP 500tests/api/evidence-failures.mjs::an_outcome_whose_directory_is_removed_during_the_wait_is_named
evidence-results-unwatchablewaiting for the outcome of run {run}the operating system stopped reporting changes to the results directory ({code}): its file watches are exhausted or the directory sits on a file system without change eventswatching {directory}: {answer}raise the watch limit of the worker's host (fs.inotify.max_user_watches on Linux) or keep {directory} on a local disk, then ask again; without wait=terminal the outcome reads at onceinfra_down, exit 69, HTTP 503, retryabletests/api/evidence-failures.mjs::an_outcome_whose_directory_cannot_be_watched_is_named
evidence-recording-root-linkedreading the named documents run {run} recordedthe run's recording root is a symbolic link or not a directory, and the worker never follows a link out of a run's tree{root}: {kind}replace {root} with the run's own directory (the worker writes it as one); the documents read as unreadable until thenconfig, exit 1, HTTP 503tests/api/evidence-failures.mjs::documents_of_a_linked_recording_root_are_named_unreadable
evidence-recording-root-outsidereading the named documents run {run} recordedthe run's recording root resolves outside the recordings directory, so reading it would serve files no run of this worker wrote{root} resolves to {real}, outside {recordings}move the run's recordings under {recordings} as a directory of their own; the documents read as unreadable until thenconfig, exit 1, HTTP 503tests/api/evidence-failures.mjs::documents_of_a_recording_root_outside_the_recordings_are_named_unreadable
captcha-answer-unawaitedkeeping the captcha answer a provider sent for run {run}no run of this worker waits for that token: the run ended, another callback already delivered it, or no run ever drew itno {token}.waiting marker for run {run}nothing to do for a repeated callback; a run still waiting for its answer has a .waiting marker in its directory under ~/.stado/weles-captcha-answers, so check the provider's callback URL names that run and tokennot_found, exit 1, HTTP 404tests/api/failures.mjs::a_captcha_answer_no_run_waits_for_is_refused
captcha-answer-unwritablekeeping the captcha answer a provider sent for run {run}the run's answers directory refused the marker check or the write: its permissions changed, or the disk is full or read-only{answer}give the worker's user write access to ~/.stado/weles-captcha-answers and free space on its disk; the provider retries its callbackinfra_down, exit 69, HTTP 500, retryabletests/api/failures.mjs::a_captcha_answer_the_run_directory_refuses_is_named
serve-identity-unreadablereading the Weles release identity {path}a release states its identity in release/source-identity.json (release/stado-build.sh writes it into the worker payload) or, for a package installed from a git archive, in the commit release/source-commit holds beside package.json; this tree has neither readable: it was checked out, or the files were removed{answer}install Weles as a release (`stado product install weles --surface service --host <this host>`, or `stado product install weles --surface cli` for the CLI package) and start it through its unit; `ls -l {path}` shows what is thereconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_without_its_release_identity_names_it
serve-release-unstatedreading which release this process isWELES_WORKER_RELEASE_VERSION is unset, or WELES_WORKER_RELEASE_SHA256 is not a lowercase SHA-256: release/stado-launcher.sh exports both from the payload it unpacked, so this process was not started as a releaseWELES_WORKER_RELEASE_VERSION: {version}; WELES_WORKER_RELEASE_SHA256: {digest}start the API through its unit (`stado product install weles --surface service --host <this host>` installs it), whose launcher exports bothconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_started_without_its_release_names_it
serve-identity-mismatchproving the release identity {path} is the deployed releasethe identity is not a weles.source-identity.v1 document of weles-worker at the version the launcher exported with a 40-digit commit: the runtime tree holds another release than the one unpackedidentity: {identity}; exported version: {version}reinstall the service (`stado product install weles --surface service --host <this host>`) so its runtime tree and launcher name one releaseconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_whose_identity_names_another_release_is_refused
serve-setting-unsetreading {name}{name} is not set: the service declaration states {meaning}, and this process was started outside it{name}: not setstart the API through its unit (`stado product install weles --surface service --host <this host>`), or set {name} to {meaning}config, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_without_its_address_names_the_variable
serve-setting-invalidreading {name}{name} is not {expected}{name}: {value}set {name} to {expected}, as the service declaration states it, or unset it where it is optionalconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_with_a_port_that_is_no_port_names_it
serve-origins-invalidreading WELES_PUBLIC_API_ALLOWED_ORIGINSit names no origin, mixes the wildcard * with origins, or holds an entry that is not an exact HTTPS origin (scheme and host, no path or trailing slash)WELES_PUBLIC_API_ALLOWED_ORIGINS: {value}; {answer}set it to * alone, or to a comma-separated list of exact https://<host> originsconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_whose_allowed_origins_are_no_origins_names_them
serve-organization-invalidreading WELES_PUBLIC_API_ORGANIZATION_IDit is not a UUID, so no task could ever name the organization it servesWELES_PUBLIC_API_ORGANIZATION_ID: {value}set it to the organization UUID the service declaration assignsconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_whose_organization_is_no_uuid_names_it
serve-receipt-key-invalidreading the receipt signing key WELES_RECEIPT_PRIVATE_KEYit is not a PEM private key, or not an Ed25519 one, which receipts are signed with{answer}set WELES_RECEIPT_PRIVATE_KEY to the Ed25519 private key the launcher acquires from Skarbiec; start the API through its unitconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_whose_receipt_key_is_no_key_names_it
serve-receipt-keys-invalidreading the receipt public keys WELES_RECEIPT_PUBLIC_KEYS_JSONit is not a JSON object of key id to PEM public key, it is empty, or it carries no key under WELES_RECEIPT_KEY_ID ({key_id}){answer}set it to the published receipt key set, which carries the public key of {key_id}config, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_whose_receipt_key_set_lacks_its_key_names_it
serve-receipt-key-mismatchproving the receipt key {key_id} against its published public keythe public key WELES_RECEIPT_PUBLIC_KEYS_JSON names for {key_id} is not the one of WELES_RECEIPT_PRIVATE_KEY, so no receipt this API signs could be verifiedthe private key derives another public key than the set publishes for {key_id}publish the public key of the private key in use under {key_id}, or acquire the private key the set namesconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_whose_receipt_key_is_not_the_published_one_is_refused
serve-policy-invalidreading the browser-evidence policy of this releasedist/agent/browser-evidence-policy/withheld-ledger.js exports no policy with a version: the release was built from a tree whose policy module moved or brokepolicy: {value}reinstall the service from a release built whole (`stado product install weles --surface service --host <this host>`)config, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_without_its_evidence_policy_names_it
serve-client-window-invalidreading WELES_CLIENT_SUPPORTED_GENERATIONSit is not an integer, so /api/v1/version could not report the client generations this worker servesWELES_CLIENT_SUPPORTED_GENERATIONS: {value}set it to the integer count of client generations the deployment serves, or unset itconfig, exit 1, HTTP 503tests/worker/launching/serve-failures.mjs::an_api_whose_client_generations_are_no_integer_names_it
pages-busyopening a page for {path}as many pages are open as the host reports processors ({limit}); nothing is queued behind a browser the caller cannot see{open} of {limit} pages are opensend the request again once an open page has answeredrate_limit, exit 69, HTTP 429, retryabletests/api/pages-failures.mjs::a_page_beyond_the_open_limit_is_refused
page-target-not-urladmitting the page {url}url does not parse as a URL{answer}send url as an absolute https://<host>/<path> addressrefused, exit 1, HTTP 422tests/api/pages-failures.mjs::a_page_target_that_is_no_url_is_refused
page-target-not-httpsadmitting the page {url}only credential-free HTTPS addresses on the default port are served, and this one is notscheme {scheme}, credentials {credentials}, port {port}send the public https:// address of the page, with no user, password or portrefused, exit 1, HTTP 422tests/api/pages-failures.mjs::a_page_target_over_plain_http_is_refused
page-target-not-publicadmitting the page {url}its host does not resolve, or resolves to loopback, link-local, private or cloud-metadata space of this worker's network{answer}send a page whose host resolves to public addresses onlyrefused, exit 1, HTTP 422tests/api/pages-failures.mjs::a_page_target_on_a_private_address_is_refused
page-no-responseloading {url}the navigation ended without an HTTP response: the page answered from its cache or was replaced before it answeredno navigation response for {url}send the address the page settles on, or a load_state the page reachesinfra_down, exit 69, HTTP 502, retryabletests/api/pages-failures.mjs::a_page_that_answers_no_response_is_named
page-http-errorloading {url}the page answered an HTTP status that is not successHTTP {status}send an address the page serves; the status names why it did notinfra_down, exit 69, HTTP 502, retryabletests/api/pages-failures.mjs::a_page_that_answers_an_http_error_is_named
page-selector-unmatchedfilling {selector} on {url}no element of the loaded page matches the selectorno element matches {selector}name a selector the page holds once it reaches the load_state asked forrefused, exit 1, HTTP 502tests/api/pages-failures.mjs::an_export_whose_field_the_page_lacks_is_named
page-button-absentpressing the export button on {url}no button of the loaded page has exactly that accessible nameno button reads "{click_text}"send click_text as the exact accessible name of the button that exportsrefused, exit 1, HTTP 502tests/api/pages-failures.mjs::an_export_whose_button_the_page_lacks_is_named
page-download-failedtaking the file {url} downloadsthe page started a download and the browser reported it failed{answer}send the request again; a download that fails each time is the page's own failureinfra_down, exit 69, HTTP 502, retryabletests/api/pages-failures.mjs::an_export_whose_download_fails_is_named
page-browser-failedrendering {url} for {path}the browser itself failed while it opened or read the page: it could not start, crashed, or timed out reaching the load state{answer}read the worker's log line event:page_route for the browser's words; `weles doctor` checks the browser runtimeinfra_down, exit 69, HTTP 502, retryabletests/api/pages-failures.mjs::a_page_the_browser_cannot_render_is_named
records-account-not-foundreading the Weles account record {account}the vault holds no live item tagged weles:record:account with that id: it was never written, or it was trashedno Weles account record {account}list the account records (POST /records/accounts/list) and name one of their idsnot_found, exit 1, HTTP 404tests/api/records-failures.mjs::a_record_of_an_account_the_vault_lacks_is_not_found
http-status-unknownreading the HTTP status "{phrase}" the routes answer withNode's HTTP status table has no status "{phrase}": the worker runs on a Node {node} whose table names it otherwise, so the server does not startnode {node}: {count} statuses, none "{phrase}"run the worker on the Node the release names (`weles worker version` and package.json engines), then `weles worker restart`unknown, exit 1, HTTP 500tests/api/routes-failures.mjs::a_node_without_a_status_phrase_is_named
captcha-run-unnamednaming the captcha answers directory of run {run}run id {run} cannot name a captcha answers directory: it is empty, holds a slash or begins with a dot, and every caller passes a run id it admitted, so this is a defect of the releaserun id {run}report it with `weles worker version` and the run that named it; no answer was writtenunknown, exit 1, HTTP 500tests/api/routes-failures.mjs::a_run_id_that_names_no_directory_is_named

settings#

11 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
setting-unsetreading {name}{name} is not set, or holds only blanks, and nothing stands in for it: it is stated, never assumed{name}: {shown}set {name} in the environment this process starts with (the release launcher states the settings of the processes it starts), then start it again; `weles doctor` reads the running API against its releaseconfig, exit 1, HTTP 503tests/settings/failures.mjs::a_setting_that_is_not_set_is_named
secret-shortreading the secret {name}{name} holds {bytes} bytes, fewer than the {minimum} a secret needs: Weles signs and compares with HMAC-SHA256, and RFC 2104 section 3 discourages a key shorter than its digest{name}: {bytes} bytesset {name} to a secret of at least {minimum} random bytes (`openssl rand -hex 32` prints one), store it where the launcher reads it, then start againconfig, exit 1, HTTP 503tests/settings/failures.mjs::a_secret_shorter_than_a_digest_is_refused
port-invalidreading the TCP port {name}{name} is not a TCP port: a port is a whole number from 1 to 65535 (RFC 9293 section 3.1; 0 names no port to listen on){name}: {value}set {name} to a whole number from 1 to 65535 that no other service on this host listens onconfig, exit 1, HTTP 503tests/settings/failures.mjs::a_port_outside_a_port_field_is_refused
count-invalidreading {name}, a number of {unit}{name} is not a whole number of {unit} above zero{name}: {value}set {name} to a whole number of {unit} above zeroconfig, exit 1, HTTP 503tests/settings/failures.mjs::a_count_that_is_no_whole_number_is_refused
origin-unsetreading {name}, the origin of the service it names{name} is not set, or holds only blanks, so this process has no address to reach that service at{name}: {shown}set {name} to the service origin (https://host[:port], or http://localhost:port on this machine), as the route Stado gives for it names, then start againconfig, exit 1, HTTP 503tests/settings/failures.mjs::an_origin_that_is_not_set_is_named
origin-not-urlreading {name}, the origin of the service it names{name} is not a URL, so it names no origin{name}: {value}set {name} to an origin such as https://host or http://localhost:8080, scheme includedconfig, exit 1, HTTP 503tests/settings/failures.mjs::an_origin_that_is_no_url_is_named
origin-credentialsreading {name}, the origin of the service it names{name} carries a user name or password in the URL; the bearer is a setting of its own and never travels in an address{name}: {value}set {name} to {origin} and keep the credential in the bearer setting the service is reached withconfig, exit 1, HTTP 503tests/settings/failures.mjs::an_origin_carrying_credentials_is_refused
origin-pathreading {name}, the origin of the service it names{name} has the path {path}; it names an origin only, and each request adds its own path{name}: {value}set {name} to {origin}config, exit 1, HTTP 503tests/settings/failures.mjs::an_origin_with_a_path_is_refused
origin-queryreading {name}, the origin of the service it names{name} has the query {query}; it names an origin only, and each request adds its own{name}: {value}set {name} to {origin}config, exit 1, HTTP 503tests/settings/failures.mjs::an_origin_with_a_query_is_refused
origin-fragmentreading {name}, the origin of the service it names{name} has the fragment {fragment}, which no request carries; it names an origin only{name}: {value}set {name} to {origin}config, exit 1, HTTP 503tests/settings/failures.mjs::an_origin_with_a_fragment_is_refused
origin-insecurereading {name}, the origin of the service it names{name} uses {protocol} to {host}, which is not this machine: a service elsewhere is reached over HTTPS, and plain HTTP only on the loopback (localhost or an address of an internal interface){name}: {value}set {name} to the service's https:// origin, or reach it through a loopback forward (`stado service directory connect SERVICE --consumer weles`)config, exit 1, HTTP 503tests/settings/failures.mjs::a_remote_plain_http_origin_is_refused

errors#

6 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
action-invalidreading the weles errors command lineerrors takes: list [--json], show <operation-or-area> [--json], or check [--root <checkout>] [--json]given: {given}run weles errors with one of list [--json], show <operation-or-area> [--json], or check [--root <checkout>] [--json]refused, exit 2, HTTP 403tests/errors/failures.mjs::errors_refuses_a_form_it_does_not_take
options-unknownreading the weles errors {action} command lineerrors {action} takes only {taken}got {given}leave out {given}: weles errors {action} {taken}refused, exit 2, HTTP 403tests/errors/failures.mjs::errors_refuses_an_option_its_action_does_not_take
operation-unknownfinding the catalogue of {id}no operation or area {id} declares a failure catalogue: it is neither an operation id nor the part of one before its dotthe operations that do: {operations}name one of those operations, or its area (`weles errors show executor` for executor.request and executor.run)refused, exit 2, HTTP 403tests/errors/failures.mjs::errors_show_of_an_operation_nobody_declares_names_those_that_do
root-missingreading errors check --rooterrors check --root needs the checkout directory, and none was given--root given without a valuegive --root <checkout>, the Weles checkout to check, or leave --root out to check the current directoryrefused, exit 2, HTTP 403tests/errors/failures.mjs::errors_check_with_an_empty_root_is_refused
root-not-a-checkoutreading the checkout errors check holds to the standarderrors check reads a Weles checkout, and {root} holds no {directory} directory{root} without {directory}run weles errors check in the checkout, or name the checkout with --root <checkout>refused, exit 2, HTTP 403tests/errors/failures.mjs::errors_check_of_a_directory_that_is_no_checkout_names_it
standard-not-metholding {root} to the error standardthe error standard is not met: a declaration is incomplete, a cause names a test that neither exists nor is listed in a part of tests/untested-causes/, the list of untested causes is itself broken, or the source says a failure happened without saying which{count} problem(s) in {root}: {problems}correct each problem where it names, write the missing test or list it with why in the last part of tests/untested-causes/ (part-<two letters>.json, a new part once it would pass 300 lines), then run weles errors check --root {root} againrefused, exit 1, HTTP 403tests/errors/failures.mjs::errors_check_of_a_checkout_that_breaks_the_standard_lists_each_problem

cli#

9 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
command-unknownreading the weles command lineunknown command: {word} is not a command weles takesthe commands weles takes: {commands}run `weles --help` for every command and its usage linesrefused, exit 2, HTTP 403tests/cli/failures.mjs::weles_refuses_a_command_it_does_not_take
verb-missingreading the weles {command} command lineweles {command} needs an action: {verbs}no action givenrun `weles {command} <action>`; `weles {command} --help` prints the usage linesrefused, exit 2, HTTP 403tests/cli/failures.mjs::onboarding_without_an_action_names_the_actions
verb-unknownreading the weles {command} command lineweles {command} takes {verbs}, not {verb}action: {verb}run `weles {command}` with one of {verbs}refused, exit 2, HTTP 403tests/cli/failures.mjs::release_refuses_an_action_it_does_not_take
arguments-invalidreading the arguments of weles {command}weles {command} takes {takes}given: {given}run `weles {command} {takes}`refused, exit 2, HTTP 403tests/cli/failures.mjs::import_without_its_file_names_what_it_takes
option-requiredreading --{option} of weles {command}--{option} is required and was given no value--{option}: {value}give --{option} <{meaning}>refused, exit 2, HTTP 403tests/cli/failures.mjs::release_enforce_without_its_decision_names_it
provider-unsupportedchoosing the provider weles {command} goes through--provider is missing or names a provider Weles has no {command} for--provider: {provider}; providers Weles takes: {providers}give --provider {providers}refused, exit 2, HTTP 403tests/cli/failures.mjs::design_through_a_provider_weles_has_none_for_is_refused
manifest-unreadablereading the Weles package manifest {path}the install carries no package.json beside its dist, or one that is not JSON: the install is incomplete or was changed after it was installed{answer}install the Weles release again through Stado (`stado product install weles`), which places dist and package.json togetherconfig, exit 1, HTTP 503tests/cli/failures.mjs::version_from_an_install_without_its_manifest_names_the_path
version-missingreading the version the Weles package manifest {path} namesthe manifest names no version: it is not the manifest a Weles release shipsversion: {version}install the Weles release again through Stado (`stado product install weles`), whose manifest names its versionconfig, exit 1, HTTP 503tests/cli/failures.mjs::version_from_a_manifest_without_a_version_names_it
node-unsupportedloading the Weles error catalogueNode {found} cannot require() the ECMAScript module @wisent/errors; Weles needs Node {needed} (package.json engines.node)node {found} at {path}: {answer}run Weles with a Node of {needed} first on PATH; `node --version` shows the one PATH findsconfig, exit 1, HTTP 503tests/cli/failures.mjs::weles_under_a_node_without_require_esm_names_both_versions

recordings#

13 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
root-unsetreading WELES_RECORDINGS_ROOTWELES_RECORDINGS_ROOT is not set: the directory that holds run recordings is declared, never assumedWELES_RECORDINGS_ROOT: {value}set WELES_RECORDINGS_ROOT to the directory runs record into (the managed worker's own setting), then run againconfig, exit 1, HTTP 503tests/recordings/failures.mjs::scrub_without_a_recordings_root_names_the_variable
root-unreadablelisting the recordings under {root}WELES_RECORDINGS_ROOT names a directory that does not exist, is not a directory, or cannot be read{answer}set WELES_RECORDINGS_ROOT to the directory runs record into, or give this user read access to it, then run againnot_found, exit 1, HTTP 404tests/recordings/failures.mjs::scrub_of_a_recordings_root_that_does_not_exist_names_it
write-denied{step} {path} for {what} of run {run}the system refused this user access to {nearest} ({errno}), so nothing can be created under it{nearest} is owned by uid {owner} with mode {mode}; this process runs as {user}; {left}give {user} write access to {nearest} (`ls -ld {nearest}` shows its owner and mode), or set WELES_RECORDINGS_ROOT to a directory it can write, then run the operation againconfig, exit 1, HTTP 503tests/recordings/write-failures.mjs::a_recording_in_a_directory_this_user_cannot_write_is_refused
write-disk-full{step} {path} for {what} of run {run}the file system holding {nearest} has no space or quota left for this user ({errno}){free} bytes free for this user on the file system of {nearest}; {left}free space on the disk holding {nearest} (`df -h {nearest}` shows it), then run the operation againinfra_down, exit 69, HTTP 503, retryabletests/recordings/write-failures.mjs::a_recording_on_a_full_disk_is_refused
write-read-only{step} {path} for {what} of run {run}the file system holding {nearest} is mounted read-only (EROFS), so no file can be written there{nearest} exists on a read-only file system; {left}set WELES_RECORDINGS_ROOT to a directory on a writable file system (`mount` shows how {nearest} is mounted), then run the operation againconfig, exit 1, HTTP 503tests/recordings/write-failures.mjs::a_recording_on_a_read_only_file_system_is_refused
write-path-blocked{step} {path} for {what} of run {run}a part of the path that must be a directory is a file ({errno}): {blocker}{blocker} exists and is not a directory; {left}move {blocker} aside or set WELES_RECORDINGS_ROOT to a directory, then run the operation againconfig, exit 1, HTTP 503tests/recordings/write-failures.mjs::a_recording_under_a_file_is_refused
write-target-directory{step} {path} for {what} of run {run}a directory already stands where the file is written (EISDIR), and a file does not replace a directory{path} is a directory holding {entries} entries; {left}move the directory {path} aside (nothing in Weles makes a directory of that name), then run the operation againconfig, exit 1, HTTP 503tests/recordings/write-failures.mjs::a_recording_where_a_directory_stands_is_refused
write-name-too-long{step} {path} for {what} of run {run}the path is longer than the file system takes (ENAMETOOLONG): its longest part {longest} characters, the whole {length} charactersthe longest part starts {start}; {left}shorten WELES_RECORDINGS_ROOT, ACTION or WELES_LABEL (the parts the path is built from), then run the operation againconfig, exit 1, HTTP 503tests/recordings/write-failures.mjs::a_recording_whose_path_is_too_long_is_refused
write-device-failed{step} {path} for {what} of run {run}the disk or file system under {nearest} failed the operation ({errno}), a fault of the device and not of the paththe system said: {problem}; {left}check the disk holding {nearest} (`diskutil verifyVolume /` on macOS, `dmesg` on Linux), then run the operation againinfra_down, exit 69, HTTP 503, retryabletests/recordings/write-failures.mjs::a_recording_the_device_fails_is_refused
write-reason-unnamed{step} {path} for {what} of run {run}the system refused the operation for a reason ({errno}) this release names no cause forthe system said: {problem}; {nearest} is owned by uid {owner} with mode {mode}; {left}look the reason {errno} up in `man 2 open` and `man 2 rename` for what the system wants of {nearest}, then run the operation againunknown, exit 1, HTTP 500tests/recordings/write-failures.mjs::a_recording_refused_for_an_unnamed_reason_is_named
action-invalidreading the weles recordings command lineweles recordings takes scrub, and {given} is not itgiven: {given}run weles recordings scrub [--json]refused, exit 2, HTTP 403tests/recordings/failures.mjs::recordings_refuses_an_action_it_does_not_take
options-unknownreading the weles recordings scrub command linerecordings scrub takes no word after it and only --jsonnot taken: {given}leave out {given}: weles recordings scrub [--json]refused, exit 2, HTTP 403tests/recordings/failures.mjs::recordings_scrub_refuses_what_it_does_not_take
scrub-incompletescrubbing the recording envelopes under {root}some session_meta.json files are not JSON, hold an env_all that is not an environment object, or could not be written back; every other envelope was scrubbed{count} envelope(s): {failures}correct or move aside each file named (its JSON or its permissions), then run weles recordings scrub again; envelopes already scrubbed stay as they areconfig, exit 1, HTTP 503tests/recordings/failures.mjs::scrub_over_an_envelope_that_is_not_one_names_it

pointer#

10 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
trace-missingreading the pointer traceno pointer trace at {path}: this Weles was released without one{path} does not existharvest it from operator-driven runs with weles pointer harvest <run>.inst.json in the Weles checkout, commit it and release; WELES_POINTER_TRACE names another file for a test journeyconfig, exit 1, HTTP 503tests/pointer/failures.mjs::show_without_a_trace_names_its_path
trace-invalidreading the pointer trace {path}{path} is not a pointer trace: it is not JSON, or not the shape weles pointer harvest writes (sources, segments of points, wheel steps){answer}harvest it from operator-driven runs with weles pointer harvest <run>.inst.json in the Weles checkout, commit it and releaseconfig, exit 1, HTTP 503tests/pointer/failures.mjs::show_of_a_trace_that_is_not_one_names_it
action-invalidreading the weles pointer command lineweles pointer takes harvest or show, and {given} is not onegiven: {given}run weles pointer harvest <run>.inst.json... [--json], or weles pointer show [--json]refused, exit 2, HTTP 403tests/pointer/failures.mjs::pointer_refuses_an_action_it_does_not_take
options-unknownreading the weles pointer {action} command linepointer {action} takes {takes}not taken: {given}leave out {given}: weles pointer {action} {takes}refused, exit 2, HTTP 403tests/pointer/failures.mjs::pointer_refuses_what_its_action_does_not_take
dumps-missingreading the dumps weles pointer harvest readspointer harvest needs at least one <run>.inst.json, and none was namedno dump namedname the instrumentation dumps of runs a person drove: weles pointer harvest <run>.inst.json...refused, exit 2, HTTP 403tests/pointer/failures.mjs::harvest_without_a_dump_is_refused
dump-unreadablereading the instrumentation dump {path}the file does not exist, cannot be read, or is not JSON, or an input it logged holds values that are not JSON{answer}name the <run>.inst.json an operator-driven run's instrumentation wrote, wholenot_found, exit 1, HTTP 404tests/pointer/failures.mjs::harvest_of_a_dump_that_is_not_one_names_it
dump-no-inputreading the page input {path} logged{path} holds no access log: the run recorded no page input, since its input recorder never ranaccesses is {accesses}name the dump of a run recorded with instrumentation on, whose access log holds the page inputrefused, exit 1, HTTP 403tests/pointer/failures.mjs::harvest_of_a_dump_without_an_access_log_names_it
no-travelharvesting pointer travel from {sources}they hold no pointer travel between two presses: no run among them had a person move the pointer from one press to another{sources}: 0 segmentsname dumps of runs a person drove, pressing at least twicerefused, exit 1, HTTP 403tests/pointer/failures.mjs::harvest_of_dumps_without_travel_names_them
no-wheelharvesting wheel steps from {sources}they hold no vertical wheel step: nobody scrolled in those runs{sources}: {segments} segments, 0 wheel stepsadd the dump of a run in which the person scrolledrefused, exit 1, HTTP 403tests/pointer/failures.mjs::harvest_of_dumps_without_scrolling_names_them
trace-unwritablewriting the harvested pointer trace to {path}the file cannot be written: its directory does not exist or this user cannot write there, as in an installed release{answer}run weles pointer harvest in the Weles checkout, whose src/human/pointer is writable, or name a writable file with WELES_POINTER_TRACEconfig, exit 1, HTTP 503tests/pointer/failures.mjs::harvest_into_a_place_that_cannot_be_written_names_it

parts#

6 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
part-unreadablereading {what} from {path}the directory or one of its parts cannot be read by this user: it is not readable, or it vanished while being read{answer}make {path} readable by this user (`ls -l {path}` shows its owner and mode), or rewrite the part from the source the document is made from, or restore the directory from the releaseconfig, exit 1, HTTP 503tests/parts/failures.mjs::a_part_that_cannot_be_read_is_named
parts-emptyreading {what} from the directory {path}the directory holds no part: none of its files ends in .json{path} holds {entries}put the document's parts (NNN.json) in {path}, or rewrite the part from the source the document is made from, or restore the directory from the releaseconfig, exit 1, HTTP 503tests/parts/failures.mjs::a_directory_without_parts_is_named
part-not-jsonreading {what} from {part}the part is not JSON: it was cut short, edited by hand into invalid syntax, or is another kind of file{part} ({bytes} bytes): {answer}correct the syntax at the place the observed message names, or rewrite the part from the source the document is made from, or restore the directory from the releaseconfig, exit 1, HTTP 503tests/parts/failures.mjs::a_part_that_is_not_json_is_named
part-not-objectreading {what} from {part}the part is JSON but not an object, so it names no member of the document{part} holds {found}, where a JSON object is expectedmake {part} an object whose members are the document's ({part} holds one slice of them), or rewrite the part from the source the document is made from, or restore the directory from the releaseconfig, exit 1, HTTP 503tests/parts/failures.mjs::a_part_that_is_not_an_object_is_named
member-repeatedmerging the parts of {what} in {path}two parts give the same value: {member} is stated by both, where only an array continues across parts and an object gains keys no other part gives{member} in {first} and again in {second}keep {member} in one of {first} and {second}config, exit 1, HTTP 503tests/parts/failures.mjs::a_member_two_parts_state_is_named
member-mixedmerging the parts of {what} in {path}member {member} is a different kind of value in two parts, so they cannot be merged{member} is {firstKind} in {first} and {secondKind} in {second}make {member} the same kind of value (an array, or an object) in every part that holds itconfig, exit 1, HTTP 503tests/parts/failures.mjs::a_member_of_two_kinds_is_named

keeper#

29 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
session-invalidfinding keeper session {session}a keeper session names one directory under ~/.weles/keeper, and this one is empty, . or .., or holds a path separatorsession: {session}name the session with one word of letters, digits, - or _, the --session the keeper was started withrefused, exit 2, HTTP 403tests/keeper/socket-failures.mjs::a_session_that_is_a_path_is_refused
keeper-not-runningasking keeper {session} {action}no keeper serves that session: it was never started under this HOME, or it stopped and removed its socketno socket at {socket}: {answer}start it with `weles keeper start --session {session}`; `weles keeper status --session {session}` says whether it runsnot_found, exit 1, HTTP 404tests/keeper/socket-failures.mjs::a_command_to_a_keeper_that_never_started_is_refused
socket-staleasking keeper {session} {action}a socket stands at that path but nothing listens on it: the keeper that made it ended without removing it (it was killed, or its host restarted){socket} refuses connections: {answer}`weles keeper stop --session {session}` removes the dead socket; `weles keeper start --session {session}` replaces it with a running keepernot_found, exit 1, HTTP 404tests/keeper/socket-failures.mjs::a_socket_nothing_listens_on_is_named_stale
socket-path-too-longreaching keeper {session} at {socket}the socket path is longer than the operating system takes for a unix socket (sun_path in sys/un.h), so no keeper can listen or be reached therethe path is {bytes} bytes; the system said: {answer}use a shorter --session, or run weles under a HOME whose path is shorter, so ~/.weles/keeper/<session>/socket fitsconfig, exit 1, HTTP 503tests/keeper/socket-failures.mjs::a_socket_path_longer_than_the_system_takes_is_named
socket-forbiddenreaching keeper {session} at {socket}this user may not connect to the socket: the keeper runs as another user, or the directory denies accessthe system said: {answer}run the command as the user that started the keeper, or give that user access to {socket}config, exit 1, HTTP 503tests/keeper/socket-failures.mjs::a_socket_this_user_may_not_open_is_named
socket-connect-failedreaching keeper {session} at {socket}reading, binding or connecting to the socket broke for a reason the system names below, other than a missing, dead, forbidden or too long socketthe system said: {answer}read the system error; once `weles keeper status --session {session}` answers, ask againinfra_down, exit 69, HTTP 503, retryabletests/keeper/socket-failures.mjs::a_socket_connection_the_system_breaks_is_named
keeper-closed-unansweredasking keeper {session} {action}the keeper accepted the connection and closed it without answering: it was stopping, or its process ended while the command ranthe connection to {socket} closed with no answer lineread `weles keeper status --session {session}`; start the keeper again if it endedinfra_down, exit 69, HTTP 503, retryabletests/keeper/socket-failures.mjs::a_keeper_that_closes_without_answering_is_named
keeper-answer-unreadablereading the answer of keeper {session} to {action}the line it answered is not JSON: what listens on the socket is not a Weles keeper, or a keeper of another releasethe answer line: {line}; the parser said: {answer}stop what listens on {socket} and start the keeper with `weles keeper start --session {session}` from this releaseconfig, exit 1, HTTP 503tests/keeper/socket-failures.mjs::a_keeper_answer_that_is_not_json_is_named
keeper-refusedasking keeper {session} {action}the keeper refused and named no cause this weles declares: it is a keeper of another release, or it ended with a failure nobody has declared yetthe keeper answered: {answer}read `weles keeper status --session {session}`; start the keeper again with this release, `weles keeper start --session {session}`refused, exit 1, HTTP 403tests/keeper/socket-failures.mjs::a_keeper_refusal_without_a_declared_cause_is_quoted
verb-unknownreading the weles keeper command lineweles keeper takes start, status, stop, not {verb}verb: {verb}run `weles keeper start|status|stop --session <id>`; `weles keeper --help` prints the usage linesrefused, exit 2, HTTP 403tests/keeper/control/control-failures.mjs::keeper_refuses_a_verb_it_does_not_take
session-missingreading the weles keeper command linekeeper {verb} needs --session <id>, the session it starts or asks--session: {session}give --session <id>, the same id each command of one keeper usesrefused, exit 2, HTTP 403tests/keeper/control/control-failures.mjs::keeper_without_a_session_is_refused
option-unknownreading the options of weles keeper {verb}keeper {verb} takes only {takes}; keeper status and stop do not start a browser, so --url and --headless belong to startoptions given: {given}run `weles keeper {verb}` with only {takes}refused, exit 2, HTTP 403tests/keeper/control/control-failures.mjs::keeper_status_with_a_start_option_is_refused
directory-foreignreading the directory of keeper {session}the session directory is not a directory a keeper made: it is a symbolic link or a file, so the socket in it may belong to anything{directory} is {kind}remove {directory} (it holds no keeper), then start the keeper with `weles keeper start --session {session}`config, exit 1, HTTP 503tests/keeper/control/control-failures.mjs::a_session_directory_that_is_a_link_is_refused
socket-foreignreading the socket of keeper {session}what stands at the socket path is not a socket, so no keeper made it and nothing can answer there{socket} is {kind}remove {socket}, then start the keeper with `weles keeper start --session {session}`config, exit 1, HTTP 503tests/keeper/control/control-failures.mjs::a_file_at_the_socket_path_is_refused
directory-unwritablemaking the directory of keeper {session}the keeper cannot create {directory}: a file stands where a directory of its path should be, or this user may not write therethe system said: {answer}make ~/.weles/keeper a directory this user can write (remove a file standing in its path), then start the keeper againconfig, exit 1, HTTP 503tests/keeper/control/control-failures.mjs::a_keeper_directory_that_cannot_be_made_is_named
socket-occupiedstarting keeper {session}another process listens on the socket of that session: another keeper serves it, and one session has one keeper{socket} accepts connectionsuse the running keeper, or stop it first with `weles keeper stop --session {session}`, or start this one under another --sessionrefused, exit 1, HTTP 403tests/keeper/control/control-failures.mjs::starting_a_session_another_keeper_serves_is_refused
start-url-failedopening --url {url} in keeper {session}the browser started but could not load the first page: the address is not a URL, its host has no DNS answer, nothing listens there, or the connection brokethe engine said: {answer}check the address answers (curl -v {url}), then start the keeper again; the browser it started was closedrefused, exit 1, HTTP 403tests/keeper/control/control-failures.mjs::a_keeper_whose_first_page_cannot_load_closes_its_browser
page-crashedserving keeper {session}the page of the keeper crashed (its renderer process ended), so the keeper closed its browser and endedthe page reported a crash at {url}start the keeper again with `weles keeper start --session {session}`; the recording of the run names the last action before the crashinfra_down, exit 69, HTTP 503, retryabletests/keeper/control/control-failures.mjs::a_keeper_whose_page_crashes_ends_naming_the_crash
answer-foreignasking keeper {session} {action}the keeper listening on that socket serves another session: it was started for another id and its socket was moved or linked herethe keeper at {socket} answered for session {answered}stop the keeper of session {answered} (`weles keeper stop --session {answered}`) and start {session} with its own socketconfig, exit 1, HTTP 503tests/keeper/control/control-failures.mjs::a_keeper_answering_for_another_session_is_refused
route-unknownanswering {method} {path}the keeper routes are GET /keepers, GET /keepers/<session> and POST /keepers/<session>/stop{method} {path}send one of those three requestsrefused, exit 2, HTTP 405tests/keeper/route-failures.mjs::a_keeper_route_the_worker_does_not_serve_is_refused
action-session-missingchoosing the keeper keeper/action askskeeper action needs SESSION, the --session of the running keeper, in its environmentSESSION: {session}run keeper/action with SESSION=<id> and the command on stdinrefused, exit 2, HTTP 403tests/keeper/control/command-failures.mjs::keeper_action_without_a_session_is_refused
command-not-objectreading a keeper commanda keeper command must be a JSON object such as {"action":"url"}, and this one is not JSON or not an object{answer}send one JSON object per line with its "action" and the fields that action needsrefused, exit 2, HTTP 403tests/keeper/control/command-failures.mjs::keeper_action_with_a_command_that_is_not_an_object_is_refused
action-unknownrunning a command in keeper {session}keeper {session} has no action {action}the actions it takes: {actions}send one of those actionsrefused, exit 2, HTTP 403tests/keeper/control/command-failures.mjs::a_keeper_command_naming_no_action_it_takes_is_refused
argument-missingrunning {action} in keeper {session}{action} needs a non-empty "{key}"{key}: {value}send "{key}" as a non-empty string with the {action} commandrefused, exit 2, HTTP 403tests/keeper/control/command-failures.mjs::a_keeper_command_without_its_text_is_refused
coordinate-missingrunning {action} in keeper {session}{action} needs a numeric "{key}", a finite number of CSS pixels{key}: {value}send "{key}" as a number with the {action} commandrefused, exit 2, HTTP 403tests/keeper/control/command-failures.mjs::a_keeper_command_without_its_coordinate_is_refused
fill-text-missingrunning fill in keeper {session}fill needs a string "text"; an empty string clears the fieldtext: {value}send "text" as a string, "" to clear the fieldrefused, exit 2, HTTP 403tests/keeper/control/command-failures.mjs::a_fill_without_its_text_is_refused
described-control-not-foundclicking the control described as {description} in keeper {session}the vision model found no control matching "{description}" on the settled pagethe page {url} shows no such controlread the page (the screenshot action saves it) and describe the control as it is labelled therenot_found, exit 1, HTTP 404tests/keeper/control/command-failures.mjs::a_described_control_the_page_does_not_show_is_named
keeper-stoppingrunning {action} in keeper {session}keeper {session} is stopping; action not started, because a stop closes its browserstate: stoppingstart the keeper again with `weles keeper start --session {session}` and send the command to itrefused, exit 1, HTTP 403tests/keeper/control/command-failures.mjs::a_command_to_a_stopping_keeper_is_refused
action-refusedrunning {action} in keeper {session} on {url}the page or the browser refused the action, in the engine words below: the element is not there, the selector does not parse, the expression threw, or the page is gonethe engine said: {answer}read the engine words and send the command again with the selector, key or expression they name correctedrefused, exit 1, HTTP 403tests/keeper/control/command-failures.mjs::a_keeper_action_the_page_refuses_quotes_the_engine

onboarding#

46 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
file-unreadablereading the {what} {path}the file could not be read ({errno}): it does not exist, is a directory, or this user may not read it{answer}give --{option} a readable JSON file: the receipt a real workflow wrote, or the map of trusted receipt keysnot_found, exit 1, HTTP 404tests/onboarding/failures.mjs::verify_with_a_receipt_that_does_not_exist_names_it
file-not-jsonreading the {what} {path}the file holds {bytes} characters that are not JSONthe parser said: {answer}give --{option} the JSON file itself: the receipt.json a workflow wrote, or the key map the worker publishesrefused, exit 1, HTTP 403tests/onboarding/failures.mjs::verify_with_a_receipt_that_is_not_json_is_refused
receipt-keys-not-objectreading the receipt key map {path}the key map holds {found}, where it is one JSON object of key ids to PEM public keysnothing was verifiedgive --keys a file such as {"<key-id>": "-----BEGIN PUBLIC KEY-----..."}, as the worker publishes its receipt keysrefused, exit 1, HTTP 403tests/onboarding/failures.mjs::verify_with_a_key_list_is_refused
receipt-keys-emptyreading the receipt key map {path}the key map is an empty object, so no receipt can verify against itnothing was verifiedadd the worker's published receipt keys to {path}refused, exit 1, HTTP 403tests/onboarding/failures.mjs::verify_with_an_empty_key_map_is_refused
receipt-key-not-pemreading the receipt key map {path}the key map's entry {key} holds {found}, not the text of a PEM public keythe map holds {count} entries; nothing was verifiedput the worker's PEM public key text under {key} in {path}refused, exit 1, HTTP 403tests/onboarding/failures.mjs::verify_with_a_key_that_is_no_text_is_refused
boundary-firstimporting existing data into onboardingcomplete the authorization-boundary step before importing existing data: an import binds drafts to a host the operator has not yet seen explainedthe journey stands at {screen}run `weles onboarding next` until the journey reaches existing-data, then importrefused, exit 1, HTTP 403tests/onboarding/failures.mjs::import_before_the_boundary_step_is_refused
step-action-unknownrunning the onboarding action {action}the journey takes no action {action}it takes {actions}; nothing was changedcall runWelesOnboarding with one of {actions} (`weles onboarding --help`)refused, exit 2, HTTP 403tests/onboarding/stages/steps-failures.mjs::an_action_the_journey_does_not_take_is_refused
step-next-at-receiptadvancing the journey from receipt-verificationthe receipt-verification step advances only on a signed receipt of a completed workflow, never on nextthe journey stands at receipt-verification; nothing was changed`weles onboarding verify --receipt <receipt.json> --keys <receipt-keys.json>`refused, exit 1, HTTP 403tests/onboarding/stages/steps-failures.mjs::next_at_the_receipt_step_is_refused
step-unadvancedadvancing the journey from {screen} by {action}the definition the attempt runs names no transition from {screen} for this evidence: {evidence}the definition came from {source}; nothing was changed`weles onboarding status --json` shows the screen and its actions; `weles onboarding reset` starts again on the current definitionunknown, exit 1, HTTP 500tests/onboarding/stages/steps-failures.mjs::a_screen_without_a_transition_for_its_evidence_is_named
step-import-earlyrecording an import in the journeycomplete the authorization-boundary step before recording an import: the journey stands at {screen}, not existing-datanothing was recordedrun `weles onboarding next` until the journey reaches existing-data, then `weles onboarding import`refused, exit 1, HTTP 403tests/onboarding/stages/steps-failures.mjs::an_import_recorded_before_the_boundary_is_refused
step-import-unpersistedrecording an import in the journeyonboarding import requires a persisted Weles import result: the report {problem}the report: {report}; nothing was recorded`weles onboarding import <trajectory-export.json> --host <host>` imports and records in one steprefused, exit 1, HTTP 403tests/onboarding/stages/steps-failures.mjs::an_import_report_without_a_draft_is_refused
step-verify-earlyverifying a receipt in the journeycomplete the authorization-boundary and host-execution steps before verifying a receipt: the journey stands at {screen}the receipt was not readrun `weles onboarding next` until the journey reaches receipt-verification, then verifyrefused, exit 1, HTTP 403tests/onboarding/stages/steps-failures.mjs::a_verify_before_host_execution_is_refused
step-verify-inputsverifying a receipt in the journeyreceipt verification requires a receipt and trusted public-key map: {missing}nothing was verifiedpass both (`weles onboarding verify --receipt <receipt.json> --keys <receipt-keys.json>`)refused, exit 2, HTTP 403tests/onboarding/stages/steps-failures.mjs::a_verify_without_keys_is_refused
step-receipt-outcome-otherverifying the receipt of task {task}verified receipt outcome is not a completed Weles workflow: it is {outcome}the receipt is signed by key {key}; the journey did not moverun an authorized workflow to completion and verify its receiptrefused, exit 1, HTTP 403tests/onboarding/stages/steps-failures.mjs::a_receipt_of_a_failed_workflow_is_refused
step-first-success-unmetcompleting the journey with the receipt of task {task}verified receipt did not satisfy the Weles first-success contract: the journey stands at {screen} and its definition completes it on no such evidencethe definition came from {source}; the journey did not move`weles onboarding status --json` shows the screen; `weles onboarding reset` starts again on the current definitionunknown, exit 1, HTTP 500tests/onboarding/stages/steps-failures.mjs::a_receipt_the_definition_does_not_complete_on_is_named
step-progress-absentstarting the journey in {directory}Weles onboarding did not create progress: start() returned without progress, a defect of the releasethe definition came from {source}install a whole Weles release (`stado product install weles --surface cli`); report it to Weles's maintainers if it persistsunknown, exit 1, HTTP 500tests/onboarding/stages/steps-failures.mjs::a_start_without_progress_is_named
step-content-missingshowing the journey screen {screen}Weles has no product content for journey screen {screen}: the definition the attempt runs names a screen this release does not renderthe definition came from {source}; this release renders {screens}install a whole Weles release (`stado product install weles --surface cli`); report it to Weles's maintainers if it persistsunknown, exit 1, HTTP 500tests/onboarding/stages/steps-failures.mjs::a_screen_this_release_does_not_render_is_named
step-bundled-invalidloading the first-use journey this release bundlesbundled Weles first-use journey identity is invalid: its {field} is {found}, where this release expects {expected}no onboarding step can runinstall a whole Weles release (`stado product install weles --surface cli`); report it to Weles's maintainers if it persistsunknown, exit 1, HTTP 500tests/onboarding/stages/steps-failures.mjs::a_bundled_journey_of_another_version_is_named
state-file-unreadreading the onboarding file {path}the file exists and could not be read ({errno}): this user may not read it, or it is a directory{problem}; nothing was changed`ls -l {path}` shows its owner and mode; `ls -l {directory}` lists the state directory; move the damaged file aside (the journey starts again from the newest good version) or name another --state-dirconfig, exit 1, HTTP 503tests/onboarding/storage-failures.mjs::a_state_file_that_cannot_be_read_is_named
state-file-not-jsonreading the onboarding file {path}the file holds {bytes} characters that are not JSON: it was cut short or written by another programthe parser said: {problem}; nothing was changed`ls -l {directory}` lists the state directory; move the damaged file aside (the journey starts again from the newest good version) or name another --state-dirconfig, exit 1, HTTP 503tests/onboarding/storage-failures.mjs::a_state_file_that_is_not_json_is_refused
journal-shapereading the onboarding file {path}the journal is not a progress map and an events list: it holds {found}version {version} of the journal; nothing was changed`ls -l {directory}` lists the state directory; move the damaged file aside (the journey starts again from the newest good version) or name another --state-dirconfig, exit 1, HTTP 503tests/onboarding/storage-failures.mjs::a_journal_of_another_shape_is_refused
journal-progress-malformedreading the onboarding file {path}the journal's progress {key} is not a journey progress record (attempt, status, screens and evidence)version {version} of the journal holds {count} progress records; nothing was changed`ls -l {directory}` lists the state directory; move the damaged file aside (the journey starts again from the newest good version) or name another --state-dirconfig, exit 1, HTTP 503tests/onboarding/storage-failures.mjs::a_journal_with_malformed_progress_is_refused
journal-event-malformedreading the onboarding file {path}queued event {index} of the journal is not a journey event (id, name, attempt and time)version {version} of the journal queues {count} events; nothing was changed`ls -l {directory}` lists the state directory; move the damaged file aside (the journey starts again from the newest good version) or name another --state-dirconfig, exit 1, HTTP 503tests/onboarding/storage-failures.mjs::a_journal_with_a_malformed_event_is_refused
state-directory-unreadlisting the onboarding state directory {directory}the directory exists and could not be listed ({errno}): it is a file, or this user may not read it{problem}; nothing was changed`ls -ld {directory}` shows what it is; name a directory of this user's with --state-dirconfig, exit 1, HTTP 503tests/onboarding/storage-failures.mjs::a_state_directory_that_cannot_be_listed_is_named
state-write-failed{step} in the onboarding state directory {directory}the system refused it ({errno}): the directory is not writable by this user, or the disk is full{problem}; {left}`ls -ld {directory}` shows its owner and mode, `df -h {directory}` its free space; correct it, then run the step againconfig, exit 1, HTTP 503tests/onboarding/storage-failures.mjs::a_state_directory_that_cannot_be_written_is_named
plane-offlineasking the onboarding control plane for {operation}this run has no control plane: {reason}the journey runs on the stored or bundled definition and its events stay queuedset WELES_STADO_INTEGRATION_TOKEN to Weles's integration bearer, and let Stado name the onboarding-events alternative (`stado capabilities resolve onboarding-events --consumer weles --json`)config, exit 1, HTTP 503tests/onboarding/stages/plane-failures.mjs::an_offline_journey_says_why
plane-origin-invalidconnecting the journey to the control plane Stado namedthe address {address} is not an HTTPS origin: it has {part}, where the control plane is reached at an origin and the journey adds the paththe journey runs on the stored or bundled definition and its events stay queued`stado capabilities resolve onboarding-events --consumer weles --json` shows the address Stado names; correct capabilities.onboarding-events.url in Stado's configurationconfig, exit 1, HTTP 503tests/onboarding/stages/plane-failures.mjs::a_control_plane_that_is_not_an_https_origin_is_refused
plane-token-emptyconnecting the journey to the control plane at {origin}the bearer handed to the transport is emptythe journey runs on the stored or bundled definition and its events stay queuedset WELES_STADO_INTEGRATION_TOKEN to Weles's integration bearerconfig, exit 1, HTTP 503tests/onboarding/stages/plane-failures.mjs::a_transport_without_a_bearer_is_refused
plane-token-malformedreading the onboarding bearer from WELES_STADO_INTEGRATION_TOKENthe variable holds {problem}, which no bearer holdsit holds {length} characters; the value is not shownset WELES_STADO_INTEGRATION_TOKEN to the bearer alone, without spaces, newlines or control charactersconfig, exit 1, HTTP 503tests/onboarding/stages/plane-failures.mjs::a_bearer_with_a_newline_is_refused
plane-product-invalidposting {operation} for {product} to the onboarding control plane at {origin}the product id {product} is not an identifier (a letter, then up to 127 letters, digits, dots, underscores or dashes), so no operation path can be made of itthe journey runs on the stored or bundled definition and its events stay queuedcall the journey with the product id its bundle declares (`weles` for Weles's own)config, exit 1, HTTP 503tests/onboarding/stages/plane-failures.mjs::a_product_id_that_is_no_identifier_is_refused
plane-unreachableposting {operation} for {product} to the onboarding control plane at {origin}the control plane did not answer ({errno}): its host is down, DNS does not resolve it, or the network is out{problem}; the journey runs on the stored or bundled definition and its events stay queued`curl -sSI {origin}` shows whether it answers from this host; the next run sends the queued eventsinfra_down, exit 69, HTTP 503, retryabletests/onboarding/stages/plane-failures.mjs::a_control_plane_that_does_not_answer_is_named
plane-answer-not-jsonposting {operation} for {product} to the onboarding control plane at {origin}the control plane answered HTTP {status} with a body that is not the JSON envelope it answers with: a proxy or another service answered at that addresscontent-type {type}, {bytes} characters: {head}; the journey runs on the stored or bundled definition and its events stay queued`stado capabilities resolve onboarding-events --consumer weles --json` shows the address Stado names; correct it in Stado's configurationinfra_down, exit 69, HTTP 503, retryabletests/onboarding/stages/plane-failures.mjs::a_control_plane_answer_that_is_not_json_is_named
plane-refusedposting {operation} for {product} to the onboarding control plane at {origin}the control plane refused the operation with HTTP {status} and error {error}the envelope said ok: {ok}; the journey runs on the stored or bundled definition and its events stay queuedHTTP 401 or 403 means the bearer in WELES_STADO_INTEGRATION_TOKEN is not Weles's; another error names what the control plane refused (`weles onboarding status --json` shows the journey)refused, exit 1, HTTP 403tests/onboarding/stages/plane-failures.mjs::a_control_plane_that_refuses_the_bearer_is_named
plane-result-absentposting {operation} for {product} to the onboarding control plane at {origin}the control plane answered HTTP {status} and ok without a result, which every operation answers withthe envelope holds {members}; the journey runs on the stored or bundled definition and its events stay queuedreport the control plane's answer to Wisent Integrations' maintainers; the journey keeps running offlineunknown, exit 1, HTTP 500tests/onboarding/stages/plane-failures.mjs::a_control_plane_answer_without_a_result_is_named
plane-bundle-foreignreading the journey {journey} version {version} from the control planethe control plane answered a bundle that is not the journey this release renders: {reason}the journey runs on the stored or bundled definition and its events stay queuedpublish journey {journey} version {version} for product weles on the control plane, or install the Weles release made for the journey it serves (`stado product install weles --surface cli`)refused, exit 1, HTTP 403tests/onboarding/stages/plane-failures.mjs::a_control_plane_bundle_of_another_version_is_refused
bundle-envelope-invalidchecking journey bundle {journey} of {product}its envelope is not a bundle's: its {field} is {found}, where a bundle carries a UUID version id, a SHA-256 content digest and its canonical definition textnothing of the bundle was believedinstall the Weles release whose bundled journey is whole (`stado product install weles --surface cli`); a control plane or stored bundle that fails this is fallen back fromunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_bundle_without_its_digest_is_refused
bundle-identity-otherchecking journey bundle {journey} of {product}its definition declares {field} {found}, where this journey is {expected}nothing of the bundle was believedinstall the Weles release whose bundled journey is whole (`stado product install weles --surface cli`); a control plane or stored bundle that fails this is fallen back fromunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_bundle_of_another_product_is_refused
bundle-experiment-invalidchecking journey bundle {journey} of {product}its experiment contract is not one: {reason}the contract holds {members}install the Weles release whose bundled journey is whole (`stado product install weles --surface cli`); a control plane or stored bundle that fails this is fallen back fromunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_bundle_whose_control_variant_is_not_eligible_is_refused
bundle-canonical-differschecking journey bundle {journey} of {product}its canonical definition text is not the canonical form of its definition: one of the two was changed after the bundle was madethe text holds {stated} characters, the definition's canonical form {computed}install the Weles release whose bundled journey is whole (`stado product install weles --surface cli`); a control plane or stored bundle that fails this is fallen back fromunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_bundle_whose_definition_was_changed_is_refused
bundle-screens-invalidchecking journey bundle {journey} of {product}its definition holds {found}, where a journey holds at least one screennothing of the bundle was believedinstall the Weles release whose bundled journey is whole (`stado product install weles --surface cli`); a control plane or stored bundle that fails this is fallen back fromunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_bundle_without_screens_is_refused
bundle-screen-invalidchecking journey bundle {journey} of {product}screen {index} ({screen}) is not one: {reason}the definition holds {count} screensinstall the Weles release whose bundled journey is whole (`stado product install weles --surface cli`); a control plane or stored bundle that fails this is fallen back fromunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_bundle_repeating_a_screen_is_refused
bundle-screen-missingchecking journey bundle {journey} of {product}the {role} {screen} names no screen of the definitionits screens are {screens}install the Weles release whose bundled journey is whole (`stado product install weles --surface cli`); a control plane or stored bundle that fails this is fallen back fromunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_bundle_whose_entry_screen_is_missing_is_refused
bundle-digest-differschecking journey bundle {journey} of {product}the SHA-256 of its canonical text is {computed}, not the content digest {stated} it states: the bundle was changed after it was signed offnothing of the bundle was believedinstall the Weles release whose bundled journey is whole (`stado product install weles --surface cli`); a control plane or stored bundle that fails this is fallen back fromunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_bundle_whose_digest_differs_is_refused
journey-screen-unknownchoosing the next screen after {screen}the progress stands at {screen}, which the definition the attempt runs does not hold: the definition changed under a started attemptits screens are {screens}`weles onboarding reset --state-dir <dir>` starts the journey again on the current definitionunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::progress_on_a_screen_the_definition_lacks_is_refused
client-identity-invalidmaking the journey client of {product}/{journey}its {field} {found} is not {shape}no attempt was startedmake the client with an identifier product and journey id and the SHA-256 hex of the subjectrefused, exit 1, HTTP 403tests/onboarding/stages/runtime-failures.mjs::a_client_for_a_subject_that_is_no_digest_is_refused
client-unstarted{step} of journey {journey}the client was asked to {step} before start() loaded a bundle and progress: a defect of the callerno progress was changed and no event queuedreport the call to Weles's maintainers; `weles onboarding status` starts the journeyunknown, exit 1, HTTP 500tests/onboarding/stages/runtime-failures.mjs::a_step_before_start_is_refused

imports#

10 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
import-host-invalidreading --host of the importit is not a host name (letters, digits, dots and hyphens, at most 253 characters), so no managed worker can be named by it--host: {host}name the managed Weles worker exactly as the registry does: --host <managed-worker-hostname>refused, exit 2, HTTP 403tests/onboarding/import-failures.mjs::an_import_for_a_host_that_is_no_host_name_is_refused
import-file-unreadablereading the trajectory export {path}no file can be read there: it does not exist, or this user may not read it{answer}name the export file a Weles export wrote, by a path this user can readnot_found, exit 1, HTTP 404tests/onboarding/import-failures.mjs::an_import_of_a_file_that_does_not_exist_names_it
import-file-not-regularreading the trajectory export {path}it is a directory or another kind of file, not the one export file an import reads{path} is not a regular filename the export file itself, not the directory holding itrefused, exit 1, HTTP 403tests/onboarding/import-failures.mjs::an_import_of_a_directory_is_refused
import-file-not-jsonreading the trajectory export {path}it is not one JSON document: it was cut short, edited by hand, or is not an exportthe parser said: {answer}export the trajectories again and import the file the export wroterefused, exit 1, HTTP 403tests/onboarding/import-failures.mjs::an_import_of_a_file_that_is_not_json_is_refused
import-export-not-objectreading the trajectory exporta trajectory export is one JSON object, and this is not oneit is a JSON {kind}import the object a Weles export writes, not a part of itrefused, exit 1, HTTP 403tests/onboarding/import-failures.mjs::an_import_of_json_that_is_not_an_object_is_refused
import-unreachableimporting the trajectory export at {endpoint}no HTTP answer came back: the host has no DNS answer, nothing listens on that port, or the connection was cut{answer}check that WELES_API_BASE names the Weles web API and that it answers there, then run againinfra_down, exit 69, HTTP 503, retryabletests/onboarding/import-failures.mjs::an_import_to_an_address_nothing_answers_on_names_it
import-unauthorizedimporting the trajectory export at {endpoint}the Weles web API did not admit WELES_TOKEN for this organization: the token is another organization's or was revokedHTTP {status}: {answer}set WELES_TOKEN to a token of the organization WISENT_ORGANIZATION_ID names, then run againauth, exit 1, HTTP 401tests/onboarding/import-failures.mjs::an_import_with_a_token_the_api_refuses_is_named
import-refusedimporting the trajectory export at {endpoint}the Weles web API understood the request and refused it; its own words below say why (an export too large, a host the organization does not hold)HTTP {status}: {answer}correct what the API names and import againrefused, exit 1, HTTP 403tests/onboarding/import-failures.mjs::an_import_the_api_refuses_quotes_it
import-failedimporting the trajectory export at {endpoint}the Weles web API, or the proxy in front of it, failed while answeringHTTP {status}: {answer}run the import again; when it fails again, the API names its failure in the words aboveinfra_down, exit 69, HTTP 503, retryabletests/onboarding/import-failures.mjs::an_import_the_api_fails_on_quotes_it
import-answer-invalidimporting the trajectory export at {endpoint}what answered is not the Weles web API's import report: a proxy or page answered instead, or the report does not count its items, organization and host as the request named them{answer}check that WELES_API_BASE names the Weles web API, not a proxy or the worker, then run againinfra_down, exit 69, HTTP 503, retryabletests/onboarding/import-failures.mjs::an_import_answered_by_something_else_is_named

skarbiec#

48 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
skarbiec-binary-unusablefinding the {label}it is not an absolute path to a regular executable file: the variable names another program, or the file Stado names is gone or not executable{answer}unset SKARBIEC_BIN so Stado names the program, or install Skarbiec through Stado (`stado release active binary skarbiec` names it)config, exit 1, HTTP 503tests/skarbiec/failures.mjs::a_skarbiec_program_that_is_not_there_is_named
skarbiec-not-attestedfinding the Skarbiec program Stado attests for this hostStado names neither a signed Skarbiec release active on this host nor the host-declared Skarbiec in ~/.stado/binstado release active binary skarbiec answered {answer}install Skarbiec on this host through Stado, so `stado release active binary skarbiec --json` names itconfig, exit 1, HTTP 503tests/skarbiec/failures.mjs::a_stado_that_attests_no_skarbiec_is_quoted
skarbiec-digest-mismatchchecking the Skarbiec program {path}its bytes are not the ones Stado's host report names: the file was replaced or changed after Stado declared itdigest {found}, Stado names {declared}reinstall Skarbiec through Stado so the file and its declaration agree againrefused, exit 1, HTTP 403tests/skarbiec/failures.mjs::a_skarbiec_program_whose_bytes_changed_is_refused
skarbiec-units-not-onereading the Skarbiec unit environment on {host}Stado declares not exactly one Skarbiec unit on that host, and the capability socket is read from exactly one{answer}declare one Skarbiec unit on {host} through Stado (`stado service env show skarbiec --host {host}` shows them)config, exit 1, HTTP 503tests/skarbiec/failures.mjs::a_host_with_no_skarbiec_unit_is_named
capability-socket-undeclaredreading the Skarbiec unit environment on {host}the one Skarbiec unit declares no absolute SKARBIEC_CAP_SOCKET for the Skarbiec unit on that hostSKARBIEC_CAP_SOCKET: {socket}set SKARBIEC_CAP_SOCKET in the Skarbiec unit environment through Stado (`stado service env set skarbiec`)config, exit 1, HTTP 503tests/skarbiec/failures.mjs::a_unit_without_a_capability_socket_is_named
resolver-action-unknownreading what skarbiec-runtime.mjs is askedit answers active-binary, endpoint or capability-socketasked: {action}run `node src/_shared/vaulting/skarbiec-runtime.mjs active-binary|endpoint|capability-socket`refused, exit 2, HTTP 403tests/skarbiec/failures.mjs::the_resolver_refuses_a_question_it_does_not_answer
vault-value-invalidreading {what} from the vaultthe vault holds it in a shape Weles does not read: {shape}; it was written by hand or by another program{answer}rewrite it in that shape with the Weles command or route that writes it, or `skarbiec set` it by handconfig, exit 1, HTTP 503tests/skarbiec/failures.mjs::a_setting_that_holds_no_json_names_it
role-invalidfinding the item that plays role {role}a role is lowercase letters, digits and hyphens, starting with a letter or digitrole: {role}name the role as `stado credentials item put --role` takes itconfig, exit 1, HTTP 503tests/runs/submitting/request-failures.mjs::a_role_that_is_not_a_role_is_refused
role-unheldfinding the item that plays role {role}no live Skarbiec item carries {tag}no item of {items} carries itstore the secret for role {role} with `stado credentials item put --host <vault owner> --role {role}`not_found, exit 1, HTTP 404tests/runs/submitting/request-failures.mjs::a_role_no_item_plays_is_named
role-ambiguousfinding the item that plays role {role}several live Skarbiec items carry {tag}, and exactly one item may play a role: reading either would be a guessitems carrying it: {holders}keep the one that should play {role} and retag the others (`stado credentials item retag`)refused, exit 1, HTTP 403tests/runs/submitting/request-failures.mjs::a_role_several_items_play_is_refused
second-factor-not-heldstarting an automated sign-in of login {item}Skarbiec judges its second factor {state}: its account is recorded to ask for {factor} after the password, and {holder}, the item keeping it, holds nothing an automated sign-in answers that with (its seed is {seed}), so the sign-in would stop there or wait on a person's phone; no browser was started and nothing was sentskarbiec login factor list {item}: state {state}, factor {factor}, holder {holder}, seed {seed}{fix}; `skarbiec login factor list {item}` says what the vault holdsconfig, exit 1, HTTP 503tests/skarbiec/factors/second-factor.mjs::a_sign_in_whose_recorded_factor_the_vault_does_not_hold_is_refused_before_the_browser
second-factor-undeclaredstarting an automated sign-in of login {item}nothing records what its account asks after the password (context.second_factor on {holder}, the item keeping its second factor), so Skarbiec judges it undeclared and Google could answer the password with a prompt on the owner's phone; no browser was started and nothing was sentskarbiec login factor list {item}: state undeclared, holder {holder}, seed {seed}{fix}; `skarbiec login factor list {item}` says what the vault holdsconfig, exit 1, HTTP 503tests/skarbiec/factors/second-factor.mjs::a_sign_in_with_no_record_and_no_working_seed_is_refused_before_the_browser
acquire-usagereading the acquisition helper's argumentsthe helper takes exactly <scope-file> <consumer> <item> <field>, and it was given {count} argument(s)arguments: {given}run node src/worker/deploy/acquire/skarbiec-acquire.mjs <scope-file> <consumer> <item> <field>refused, exit 2, HTTP 403tests/skarbiec/acquisition-failures.mjs::an_acquisition_without_its_four_arguments_is_refused
acquire-coordinate-invalidasking for {consumer} on {item}#{field}the {part} {value} is not an exact name (letters, digits, . _ and -){role}{part}: {value}name the consumer and field exactly, and the item as an exact name or role:<exact name>refused, exit 2, HTTP 403tests/skarbiec/acquisition-failures.mjs::an_acquisition_of_a_coordinate_that_is_no_name_is_refused
acquire-scope-catalog-absentchecking that the scope catalog {scope_file} declares {consumer} on {item}#{field}no file is at {scope_file}{answer}set SKARBIEC_WELES_ACQUISITION_SCOPES_FILE to the catalog the release ships, or unset it so the release's own is readconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_scope_catalog_is_missing_is_refused
acquire-scope-catalog-unreadablechecking that the scope catalog {scope_file} declares {consumer} on {item}#{field}the catalog cannot be read ({error_code}): it is a directory, or this user may not read it{answer}make {scope_file} a file this user can read (`ls -l {scope_file}` shows its owner and mode)config, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_scope_catalog_is_a_directory_is_refused
acquire-scope-row-invalidchecking that the scope catalog {scope_file} declares {consumer} on {item}#{field}line {line} is not one consumer|item|field of exact namesline {line}: {row}correct the catalog so each line is one consumer|item|field (item an exact name or role:<exact name>), once; the release ships src/worker/deploy/acquire/skarbiec-acquisition-scopes.confconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_scope_catalog_holds_a_malformed_row_is_refused
acquire-scope-catalog-emptychecking that the scope catalog {scope_file} declares {consumer} on {item}#{field}the catalog declares no scope at all ({lines} line(s), every one blank or a comment){lines} line(s), no scopecorrect the catalog so each line is one consumer|item|field (item an exact name or role:<exact name>), once; the release ships src/worker/deploy/acquire/skarbiec-acquisition-scopes.confconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_scope_catalog_is_empty_is_refused
acquire-scope-repeatedchecking that the scope catalog {scope_file} declares {consumer} on {item}#{field}line {line} repeats the scope line {first} declares, so the catalog is not one list of distinct grantsline {line}: {row}correct the catalog so each line is one consumer|item|field (item an exact name or role:<exact name>), once; the release ships src/worker/deploy/acquire/skarbiec-acquisition-scopes.confconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_scope_catalog_repeats_a_scope_is_refused
acquire-scope-undeclaredchecking that the scope catalog {scope_file} declares {consumer} on {item}#{field}none of its {declared} declared scopes is {consumer}|{item}|{field}, so the workload never asks Skarbiec for it{declared} declared scopes in {scope_file}add the line {consumer}|{item}|{field} to the catalog the release ships, with the Skarbiec grant it stands for, or ask for a declared scopeconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_undeclared_scope_is_refused_before_skarbiec_is_asked
acquire-workload-id-invalidnaming the workload that asks for {consumer} on {item}#{field}SKARBIEC_WORKLOAD_ID is {why}, where it is nonempty text without surrounding space or control charactersSKARBIEC_WORKLOAD_ID: {shown}set SKARBIEC_WORKLOAD_ID to the name Skarbiec's workload registry knows this service by, as its service unit declares itconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_without_a_workload_id_is_refused
acquire-signing-key-path-invalidproving the workload {workload} for {consumer} on {item}#{field}SKARBIEC_WORKLOAD_SIGNING_KEY_FILE is {shown}, which is not an absolute pathSKARBIEC_WORKLOAD_SIGNING_KEY_FILE: {shown}point SKARBIEC_WORKLOAD_SIGNING_KEY_FILE at the workload key Skarbiec's workload registry holds the public half of (a regular file of this user, mode 600), as the service unit declares itconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_with_a_relative_signing_key_path_is_refused
acquire-signing-key-absentproving the workload {workload} for {consumer} on {item}#{field}no file is at {key_file}, so the workload cannot sign its proof{answer}point SKARBIEC_WORKLOAD_SIGNING_KEY_FILE at the workload key Skarbiec's workload registry holds the public half of (a regular file of this user, mode 600), as the service unit declares itconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_signing_key_is_missing_is_refused
acquire-signing-key-unreadableproving the workload {workload} for {consumer} on {item}#{field}the signing key {key_file} cannot be read ({error_code}){answer}point SKARBIEC_WORKLOAD_SIGNING_KEY_FILE at the workload key Skarbiec's workload registry holds the public half of (a regular file of this user, mode 600), as the service unit declares itconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_signing_key_cannot_be_read_is_refused
acquire-signing-key-unsafeproving the workload {workload} for {consumer} on {item}#{field}the signing key {key_file} {why}: it is a regular file this user (uid {uid}) owns, closed to group and otherstype {type}; owner uid {owner}; mode {mode}point SKARBIEC_WORKLOAD_SIGNING_KEY_FILE at the workload key Skarbiec's workload registry holds the public half of (a regular file of this user, mode 600), as the service unit declares it; `chmod 600 {key_file}` closes it to othersconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_signing_key_others_can_read_is_refused
acquire-signing-key-unusableproving the workload {workload} for {consumer} on {item}#{field}the file {key_file} ({bytes} bytes) holds no private key the workload can sign with (a PEM Ed25519 key){answer}point SKARBIEC_WORKLOAD_SIGNING_KEY_FILE at the workload key Skarbiec's workload registry holds the public half of (a regular file of this user, mode 600), as the service unit declares itconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_signing_key_is_no_key_is_refused
acquire-authority-unreachableSkarbiec {stage} at {origin} for {consumer} on {item}#{field}Skarbiec did not answer POST {path}: nothing listens at {origin}, the forward to it is down, or the network refused the connection{answer}`stado capabilities resolve secrets --consumer weles --json` shows the route Stado names; ask again once it answersinfra_down, exit 69, HTTP 503, retryabletests/skarbiec/acquisition-failures.mjs::an_acquisition_from_a_skarbiec_that_does_not_answer_names_it
acquire-field-absentSkarbiec {stage} at {origin} for {consumer} on {item}#{field}Skarbiec answered HTTP {status}: the item carries no field {field}POST {path}: HTTP {status}: {detail}; asserted workload {workload}store {field} on the item (or the role's item), or ask for a field it carriesnot_found, exit 1, HTTP 404tests/skarbiec/acquisition-failures.mjs::an_acquisition_of_a_field_the_item_lacks_names_it
acquire-workload-unauthorizedSkarbiec {stage} at {origin} for {consumer} on {item}#{field}Skarbiec answered HTTP {status}: no grant covers {consumer} for the workload {workload}, or its proof was not acceptedPOST {path}: HTTP {status}: {detail}; asserted workload {workload}grant the workload acquire:{item}#{field} for {consumer} in Skarbiec, or check the host's clock and workload keyauth, exit 1, HTTP 401tests/skarbiec/acquisition-failures.mjs::an_acquisition_no_grant_covers_names_it
acquire-grant-endedSkarbiec {stage} at {origin} for {consumer} on {item}#{field}Skarbiec answered HTTP {status}: the acquire grant covering {consumer} for the workload {workload} has ended (Skarbiec's error grant_ended)POST {path}: HTTP {status}: {detail}; asserted workload {workload}register the acquisition catalog with Skarbiec again as its answer says; restarting the service does not renew a grantauth, exit 1, HTTP 401tests/skarbiec/acquisition-failures.mjs::an_acquisition_whose_grant_ended_names_it
acquire-refusedSkarbiec {stage} at {origin} for {consumer} on {item}#{field}Skarbiec answered HTTP {status}: Skarbiec refused the {stage} for a reason its answer namesPOST {path}: HTTP {status}: {detail}; asserted workload {workload}correct what Skarbiec names; `stado service logs skarbiec` shows its siderefused, exit 1, HTTP 403tests/skarbiec/acquisition-failures.mjs::an_acquisition_skarbiec_refuses_quotes_it
acquire-answer-unreadSkarbiec {stage} at {origin} for {consumer} on {item}#{field}Skarbiec answered HTTP {status} to POST {path} and the connection broke before its body was read{answer}ask again; if it repeats, `stado service logs skarbiec` shows whyinfra_down, exit 69, HTTP 503, retryabletests/skarbiec/acquisition-failures.mjs::an_acquisition_answer_cut_off_is_named
acquire-answer-not-jsonSkarbiec {stage} at {origin} for {consumer} on {item}#{field}Skarbiec answered HTTP {status} to POST {path} with a body that is not JSON: the route reaches something other than Skarbiec{bytes} bytes; parser: {answer}`stado capabilities resolve secrets --consumer weles --json` shows the route Stado names; it must reach Skarbiecconfig, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_answer_that_is_not_json_is_named
acquire-bearer-invalidSkarbiec {stage} at {origin} for {consumer} on {item}#{field}the bearer Skarbiec issued is not bound to exactly {consumer}, {item} and {field} with a token and an expiry: {why}fields {fields}compare Skarbiec's release with the acquisition protocol this helper speaks (POST /v1/acquisitions answers consumer, expires_at, field, item, token, until_revoked)config, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_bearer_bound_elsewhere_is_named
acquire-value-invalidSkarbiec {stage} at {origin} for {consumer} on {item}#{field}the one-time read did not answer exactly the bound field as nonempty text: {why}shape {shape}; the value is not showncompare Skarbiec's release with the acquisition protocol this helper speaks (POST /v1/acquisitions/read answers consumer, field, item, value and an optional provider)config, exit 1, HTTP 503tests/skarbiec/acquisition-failures.mjs::an_acquisition_read_of_another_shape_is_named
write-usagereading the write helper's argumentsthe helper takes <consumer> <item|role:ROLE> <field> <absolute-token-file> <operation> <operation-id>, and {why}arguments: {given}run node src/worker/deploy/acquire/skarbiec-write.mjs <consumer> <item|role:ROLE> <field> <absolute-token-file> <operation> <operation-id> with the payload on standard inputrefused, exit 2, HTTP 403tests/skarbiec/write-failures.mjs::a_write_without_its_six_arguments_is_refused
write-token-unreadreading the writer token for {consumer} writing {item}#{field} ({mode})the token file {token_file} cannot be read ({error_code}){answer}state the writer token file Stado provisioned for {consumer} (a regular file of this user, mode 600)config, exit 1, HTTP 503tests/skarbiec/write-failures.mjs::a_write_whose_token_file_is_missing_is_refused
write-token-invalidreading the writer token for {consumer} writing {item}#{field} ({mode})the token file {token_file} holds {why}, which is no bearer{bytes} bytes; the value is not shownwrite the token Skarbiec issued to {consumer} into {token_file}, without a trailing newlineconfig, exit 1, HTTP 503tests/skarbiec/write-failures.mjs::a_write_whose_token_holds_whitespace_is_refused
write-payload-not-jsonreading the payload of {consumer} writing {item}#{field} ({mode})the {bytes} bytes on standard input are not JSONparser: {answer}; the payload is not shownpass one skarbiec.item.v2 item on standard input whose fields carry {field}, as writeWelesAcquiredSecret builds itrefused, exit 1, HTTP 403tests/skarbiec/write-failures.mjs::a_write_of_a_payload_that_is_not_json_is_refused
write-payload-shapereading the payload of {consumer} writing {item}#{field} ({mode})the payload is not one skarbiec.item.v2 item carrying {field}: {why}members {members}; the values are not shownpass one skarbiec.item.v2 item on standard input whose fields carry {field}, as writeWelesAcquiredSecret builds itrefused, exit 1, HTTP 403tests/skarbiec/write-failures.mjs::a_write_of_a_payload_without_its_field_is_refused
write-capture-origin-invalidreading the payload of {consumer} writing {item}#{field} ({mode})the payload's capture_origin {found} is not one absolute https origin, which Skarbiec requires the write to echocapture_origin: {found}state capture_origin as https://<host> exactly as the acquisition declared it, or leave it outrefused, exit 1, HTTP 403tests/skarbiec/write-failures.mjs::a_write_with_a_capture_origin_that_is_no_origin_is_refused
write-unreachablePUT {origin}/v1/items for {consumer} writing {item}#{field} ({mode})Skarbiec did not answer: nothing listens at {origin}, the forward to it is down, or the network refused the connection{answer}`stado capabilities resolve secrets --consumer weles --json` shows the route Stado names; write again once it answersinfra_down, exit 69, HTTP 503, retryabletests/skarbiec/write-failures.mjs::a_write_to_a_skarbiec_that_does_not_answer_names_it
write-bearer-refusedPUT {origin}/v1/items for {consumer} writing {item}#{field} ({mode})Skarbiec answered HTTP {status}: it does not accept the writer token of {consumer}HTTP {status}: {detail}state the token Skarbiec issued to {consumer} in {token_file}auth, exit 1, HTTP 401tests/skarbiec/write-failures.mjs::a_write_skarbiec_refuses_the_bearer_for_is_named
write-skarbiec-failingPUT {origin}/v1/items for {consumer} writing {item}#{field} ({mode})Skarbiec answered HTTP {status}: Skarbiec failed on its side, so nothing was writtenHTTP {status}: {detail}write again later; `stado service logs skarbiec` shows why it failsinfra_down, exit 69, HTTP 503, retryabletests/skarbiec/write-failures.mjs::a_write_skarbiec_fails_on_is_named
write-refusedPUT {origin}/v1/items for {consumer} writing {item}#{field} ({mode})Skarbiec answered HTTP {status}: Skarbiec refused the write for a reason its answer namesHTTP {status}: {detail}correct what Skarbiec names (the grant, the mode, the origin); `stado service logs skarbiec` shows its siderefused, exit 1, HTTP 403tests/skarbiec/write-failures.mjs::a_write_skarbiec_refuses_quotes_it
write-answer-unreadPUT {origin}/v1/items for {consumer} writing {item}#{field} ({mode})Skarbiec answered HTTP {status} and the connection broke before its body was read, so the write is not acknowledged{answer}write again with the same operation id; Skarbiec keeps one item per operationinfra_down, exit 69, HTTP 503, retryabletests/skarbiec/write-failures.mjs::a_write_answer_cut_off_is_named
write-answer-not-jsonPUT {origin}/v1/items for {consumer} writing {item}#{field} ({mode})Skarbiec answered HTTP {status} with a body that is not JSON: the route reaches something other than Skarbiec{bytes} bytes beginning {body}; parser: {answer}`stado capabilities resolve secrets --consumer weles --json` shows the route Stado names; it must reach Skarbiecconfig, exit 1, HTTP 503tests/skarbiec/write-failures.mjs::a_write_answer_that_is_not_json_is_named
write-unacknowledgedPUT {origin}/v1/items for {consumer} writing {item}#{field} ({mode})Skarbiec answered HTTP {status} without acknowledging {item}: {why}answer: {body}compare Skarbiec's release with the write this helper makes (PUT /v1/items answers ok: true and the item's id)config, exit 1, HTTP 503tests/skarbiec/write-failures.mjs::a_write_skarbiec_does_not_acknowledge_is_named

broker#

6 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
broker-socket-missingasking the capability broker on {socket} of this machine ({machine}) for its statusnothing exists at that path: the Skarbiec unit of this machine is not running, or it listens on a socket other than the one Stado declares for it{socket}: {answer}start the Skarbiec unit of {machine} through Stado, or correct SKARBIEC_CAP_SOCKET in its declaration; `stado service status skarbiec` shows whether the Skarbiec unit of {machine} runs; `skarbiec capability status --socket {socket}` asks the broker as Weles didinfra_down, exit 69, HTTP 503, retryabletests/secrets/broker-status-failures.mjs::a_socket_nothing_created_is_named
broker-socket-staleasking the capability broker on {socket} of this machine ({machine}) for its statusthe socket file exists but no process listens on it: the broker that created it ended without removing it{socket} ({state}): {answer}restart the Skarbiec unit of {machine} through Stado so its broker listens again; `stado service status skarbiec` shows whether the Skarbiec unit of {machine} runs; `skarbiec capability status --socket {socket}` asks the broker as Weles didinfra_down, exit 69, HTTP 503, retryabletests/secrets/broker-status-failures.mjs::a_socket_nobody_listens_on_is_named
broker-socket-forbiddenasking the capability broker on {socket} of this machine ({machine}) for its statusthe operating system refused this process (user {user}) the socket: its owner or mode admits another user only{socket} ({state}): {answer}run the Weles API as the user the Skarbiec unit admits, or let the Skarbiec unit grant that user the socket, through their Stado declarationsconfig, exit 1, HTTP 503tests/secrets/broker-status-failures.mjs::a_socket_this_user_may_not_open_is_named
broker-socket-unreachableasking the capability broker on {socket} of this machine ({machine}) for its statusthe connection failed for a reason other than a missing, dead or forbidden socket (the system error {errno}){socket} ({state}): {answer}correct what the system error names, then let the unit start again; `stado service status skarbiec` shows whether the Skarbiec unit of {machine} runs; `skarbiec capability status --socket {socket}` asks the broker as Weles didinfra_down, exit 69, HTTP 503, retryabletests/secrets/broker-status-failures.mjs::a_socket_connection_the_system_breaks_is_named
broker-answer-incompleteasking the capability broker on {socket} of this machine ({machine}) for its statusthe broker closed the connection before it ended its status line{length} characters without a line end: {answer}retry; a broker that keeps doing it is failing, `stado service status skarbiec` shows whether the Skarbiec unit of {machine} runs; `skarbiec capability status --socket {socket}` asks the broker as Weles didinfra_down, exit 69, HTTP 503, retryabletests/secrets/broker-status-failures.mjs::a_broker_that_hangs_up_mid_answer_is_named
broker-answer-invalidasking the capability broker on {socket} of this machine ({machine}) for its statusits status line is not the {version} listening status with a process id that Skarbiec answers: another program holds the socket, or the broker speaks another version{answer}find what listens on {socket} (`lsof {socket}`) and let only this machine's Skarbiec broker hold it; `stado service status skarbiec` shows whether the Skarbiec unit of {machine} runs; `skarbiec capability status --socket {socket}` asks the broker as Weles didconfig, exit 1, HTTP 503tests/secrets/broker-status-failures.mjs::a_broker_answer_that_is_no_status_is_named

integrations#

9 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
integrations-bearer-unsetreaching the {family} family for {domain}/{action}WELES_STADO_INTEGRATION_TOKEN, Weles's own bearer for the action boundary, is {value}WELES_STADO_INTEGRATION_TOKEN: {value}set WELES_STADO_INTEGRATION_TOKEN in the Weles service's environment through Stado (`stado service env set weles`), then run it againconfig, exit 1, HTTP 503tests/integrations/failures.mjs::a_run_without_its_bearer_is_refused_before_stado_is_asked
integrations-unansweredresolving the {family} family for weles, for {domain}/{action}Stado names no alternative that answers it: the family is unknown to this Stado, or none of its alternatives answers{answer}repair what Stado names (`stado capabilities select {family} --order ...` puts one that answers in the order); `stado capabilities resolve {family} --consumer weles` shows the alternative Stado namesinfra_down, exit 69, HTTP 503, retryabletests/integrations/failures.mjs::a_family_stado_does_not_resolve_is_quoted
integrations-alternative-invalidresolving the {family} family for weles, for {domain}/{action}the alternative Stado named is no wisent-integrations route Weles can call: an HTTPS origin, or HTTP to this machine's loopback, without credentials, path, query or fragment{answer}correct the address (`stado config set capabilities.{family}.url <https origin>`); `stado capabilities resolve {family} --consumer weles` shows the alternative Stado namesconfig, exit 1, HTTP 503tests/integrations/failures.mjs::an_alternative_that_is_no_route_is_named
integrations-unreachablethe action {domain}/{action} at {endpoint}no HTTP answer came back, also after Stado proved the route again: the boundary is down or the address does not lead to it{answer}check that Wisent Integrations answers at {route}; `stado capabilities resolve {family} --consumer weles` shows the alternative Stado namesinfra_down, exit 69, HTTP 503, retryabletests/integrations/failures.mjs::a_boundary_that_does_not_answer_is_named
integrations-unauthorizedthe action {domain}/{action} at {endpoint}the boundary refused Weles's bearer (HTTP {status}): WELES_STADO_INTEGRATION_TOKEN is not one it admits, or it may not act for {domain} as {identity}HTTP {status}: {answer}mint Weles's integration bearer again and set it as WELES_STADO_INTEGRATION_TOKEN (`stado service env set weles`), or let Wisent Integrations admit it for {domain}auth, exit 1, HTTP 401tests/integrations/failures.mjs::a_bearer_the_boundary_refuses_is_named
integrations-action-refusedthe action {domain}/{action} at {endpoint}the boundary or the provider behind it refused the action as asked (HTTP {status}): its own error names whyHTTP {status}: {answer}correct what the provider's error names (the id, the channel, the domain, the identity's scopes) and run it againrefused, exit 1, HTTP 403tests/integrations/failures.mjs::an_action_the_provider_refuses_is_quoted
integrations-rate-limitedthe action {domain}/{action} at {endpoint}the boundary or the provider behind it is limiting this identity (HTTP {status})HTTP {status}: {answer}wait the time the answer names, then run it againrate_limit, exit 69, HTTP 429, retryabletests/integrations/failures.mjs::an_action_the_provider_limits_is_named
integrations-boundary-failingthe action {domain}/{action} at {endpoint}the boundary failed on its side (HTTP {status})HTTP {status}: {answer}retry; when it persists, read the Wisent Integrations log for {domain}/{action}infra_down, exit 69, HTTP 503, retryabletests/integrations/failures.mjs::a_boundary_that_fails_is_named
integrations-answer-invalidthe action {domain}/{action} at {endpoint}the answer is not the `{ok: true, result}` envelope the boundary answers with, or its result lacks what the caller reads: {problem}HTTP {status}: {answer}check that {route} is Wisent Integrations and not another service; `stado capabilities resolve {family} --consumer weles` shows the alternative Stado namesinfra_down, exit 69, HTTP 503, retryabletests/integrations/failures.mjs::an_answer_that_is_no_envelope_is_named

records#

15 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
record-id-invalidnaming a Weles recorda record id is an item id: a letter or digit, then letters, digits, `_`, `.`, `:` or `-`id: {id}name the record by the id its list answeredrefused, exit 1, HTTP 403tests/records/failures.mjs::a_record_id_that_is_no_item_id_is_refused
record-invalidwriting Weles record {id}{what} must be {shape}; nothing was written{answer}hand the record over in that shaperefused, exit 1, HTTP 403tests/records/failures.mjs::an_account_without_metadata_is_refused
argument-missingreading the arguments of {program} {command}{command} takes {name}, and none was given; nothing was writtenarguments: {given}run `node {program} {usage}`refused, exit 2, HTTP 403tests/records/failures.mjs::a_subscription_command_without_its_id_is_refused
command-unknownreading the command {program} is askedit answers {usage}asked: {command}run `node {program} {usage}`refused, exit 2, HTTP 403tests/records/failures.mjs::a_records_program_asked_what_it_does_not_answer_is_refused
json-argument-invalidreading {name} of {program} {command}it is not JSON; nothing was written{answer}pass {name} as one JSON object argument, quoted for the shellrefused, exit 2, HTTP 403tests/records/failures.mjs::a_subscription_row_that_is_not_json_is_refused
subscription-not-objectreading the subscription {what}it must be a JSON object; nothing was written{what}: {answer}pass the {what} as one JSON objectrefused, exit 1, HTTP 403tests/records/failures.mjs::a_subscription_row_that_is_not_an_object_is_refused
observation-incompleterecording the subscription of {service}/{account}it has no {missing}: what was observed, and when, is the collector's to state; nothing was writtenmissing: {missing}state service_name, provider, account_identifier, status, last_verified_at and a metadata objectrefused, exit 1, HTTP 403tests/records/failures.mjs::a_subscription_without_its_observation_is_refused
observed-at-invalidrecording the subscription of {service}/{account}subscription last_verified_at must be a date-time the collector observed; nothing was writtenlast_verified_at: {value}state last_verified_at as an ISO 8601 date-timerefused, exit 1, HTTP 403tests/records/failures.mjs::a_subscription_observed_at_no_time_is_refused
observation-splitupdating subscription record {id}subscription status and last_verified_at must be supplied together for a new observation; nothing was writtenthe patch names {named}send status and last_verified_at in one patchrefused, exit 1, HTTP 403tests/records/failures.mjs::a_status_without_its_observation_time_is_refused
subscription-not-foundreading service subscription record {id}no live vault item tagged weles:record:service-subscription has that id: it was deleted, or it is another recordservice subscription record {id} not found among {count} recordstake the id from `node src/lib/subscribing/service_subscriptions.mjs list`not_found, exit 1, HTTP 404tests/records/failures.mjs::a_subscription_that_does_not_exist_is_not_found
subscription-unreadablereading service subscription record {id}the item is tagged weles:record:service-subscription and its context carries no subscription object: it was written by hand or by another programcontext: {context}write it again with `node src/lib/subscribing/service_subscriptions.mjs upsert`, or remove its tagconfig, exit 1, HTTP 503tests/records/failures.mjs::a_subscription_item_without_its_subscription_is_named
credential-id-invalidnaming the service credentiala credential id is an item id: a letter or digit, then letters, digits, `_`, `.`, `:` or `-`; nothing was writtenid: {id}name the credential by an item idrefused, exit 1, HTTP 403tests/records/failures.mjs::a_credential_id_that_is_no_item_id_is_refused
login-method-missingwriting service credential {id}it states no login_method; say how the account signs in; nothing was writtenlogin_method: {value}state login_method (password, google_sso, ...)refused, exit 1, HTTP 403tests/records/failures.mjs::a_credential_without_its_login_method_is_refused
kimi-address-missingconfiguring Kimi credential {id} for Google sign-inensure-kimi-google-sso needs the Google account address: pass it, or name a source credential that carries login_emailsource credential: {source}run `node src/lib/service_credentials.mjs ensure-kimi-google-sso <id> <source> <email>`refused, exit 1, HTTP 403tests/records/failures.mjs::a_kimi_credential_without_an_address_is_refused
credential-unreadablereading service credential {id}the item carries no fields or no context object: it was written by hand or by another program{answer}write it again with `node src/lib/service_credentials.mjs patch {id} <json>`config, exit 1, HTTP 503tests/records/failures.mjs::a_credential_item_without_its_context_is_named

doctor#

12 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
recording-runtime-unresolvedresolving the Playwright recording runtimePlaywright's browser manifest cannot be read, lists no browsers, declares no ffmpeg revision, or resolves no bundled ffmpeg executable{answer}reinstall the Weles release through Stado, whose payload carries Playwright and its browser manifestconfig, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_without_a_playwright_manifest_names_it
recording-encoder-brokenprobing {command}the ffmpeg encoder Playwright records video with is missing, not a regular file, not executable, or fails to run, so every recorded browser task on this host fails{answer}repair the packaged recording runtime: install it with `npx playwright install ffmpeg` where PLAYWRIGHT_BROWSERS_PATH points, or reinstall the Weles release through Stadoconfig, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_without_the_recording_encoder_names_it
service-install-unreadablereading the installed Weles service {root}the directory exists and cannot be listed: its permissions or the disk refuse it{answer}give this user read access to {root}, or reinstall the service with `stado product install weles --surface service`config, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_over_an_install_it_cannot_list_names_it
service-platform-absentchoosing the platform of the installed Weles service {root}STADO_PLATFORM names {platform}, and {payload} is absent: no release for that platform is installedthe installed platforms are {platforms}set STADO_PLATFORM to the platform this host runs, or install its release with `stado product install weles --surface service`config, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_with_a_platform_nothing_is_installed_for_names_it
service-platform-ambiguouschoosing the platform of the installed Weles service {root}several platforms hold a payload, and nobody set STADO_PLATFORM to choose oneseveral Weles service payloads are installed: {payloads}set STADO_PLATFORM to the platform this host runsconfig, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_over_two_installed_platforms_without_a_choice_names_them
service-payload-unreadablehashing the installed payload {payload}the payload exists and cannot be read: its permissions refuse it, or it is not a regular file{answer}reinstall the service with `stado product install weles --surface service`config, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_over_a_payload_it_cannot_read_names_it
service-address-invalidreading the Weles API address {variable} namesit is not an http(s) URL, or WELES_API_PORT is not a TCP port from 1 to 65535{variable}: {value}set WELES_WORKER_API_BASE to the API URL, or WELES_API_PORT to the port its service declaration assignsconfig, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_with_an_api_address_that_is_not_a_url_names_it
service-unreachablethe Weles API at {address} could not be readnothing accepts a connection there: the Weles service of this host is stopped, or the address names another port{answer}start the service from what is installed with `stado service ensure weles --host <this host> --reason <why>`, or correct WELES_WORKER_API_BASE or WELES_API_PORTinfra_down, exit 69, HTTP 503, retryabletests/doctor/failures.mjs::doctor_whose_api_address_nothing_answers_names_it
service-health-refusedthe Weles API at {address} could not be readits /healthz answers an HTTP error, not the service identity{address}/healthz answered HTTP {status}read why with `stado service logs weles`, then start it from what is installed with `stado service ensure weles --host <this host> --reason <why>`infra_down, exit 69, HTTP 503, retryabletests/doctor/failures.mjs::doctor_whose_api_answers_an_http_error_names_it
service-not-welesthe Weles API at {address} could not be readwhat answers there is not the Weles API: its /healthz is not JSON naming source weles_api{address}/healthz names {source}, not weles_apicorrect WELES_WORKER_API_BASE or WELES_API_PORT to the port the Weles service declaration assignsconfig, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_whose_api_is_another_program_names_it
service-not-installedcomparing the Weles API at {address} with the installed releaseno weles-worker release is installed under {root}, so Stado did not install what answers on this portthe Weles API at {address} serves {served}install the release with `stado product install weles --surface service`config, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_whose_api_has_no_installed_release_names_it
service-release-mismatchcomparing the Weles API at {address} with the installed releasethe running process is not the installed release: it did not restart onto it, or another release holds the portthe Weles API at {address} serves {served}, while the installed payload {payload} is sha256 {sha256}start it from what is installed with `stado service ensure weles --host <this host> --reason <why>`config, exit 1, HTTP 503tests/doctor/failures.mjs::doctor_whose_api_serves_another_release_names_both

capture#

13 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
param-not-objectreading the {action} parameters{action} requires {name} as an object.{name}: {value}send {name} as a JSON objectrefused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_viewport_that_is_not_an_object_is_refused
param-not-slugreading the {action} parameters{action} requires {name} as a lowercase slug of letters, digits, dot, dash or underscore.{name}: {value}send {name} as at most 81 such characters, starting with a letter or digitrefused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_batch_that_is_not_a_slug_is_refused
source-url-invalidreading the {action} parameters{action} requires {name} as an http(s) URL.{name}: {value}send {name} as an absolute http:// or https:// addressrefused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_source_url_that_is_not_http_is_refused
param-not-integerreading the {action} parameters{action} rejects {name} {value}: {name} must be an integer between {min} and {max}.{name}: {value}send {name} as a whole number from {min} to {max}refused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_viewport_width_of_zero_is_refused
scale-not-positivereading the {action} parameters{action} rejects viewport.device_scale_factor {value}: device_scale_factor must be a positive number.viewport.device_scale_factor: {value}send device_scale_factor as a number above zero, or leave it out for 1refused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_device_scale_factor_of_zero_is_refused
artifact-prefix-invalidreading the {action} parameters{action} rejects artifact_prefix {value}: {reason}artifact_prefix: {value}send artifact_prefix as {root}<segment>/.../ of letters, digits, dot, dash or underscore, ending with a slashrefused, exit 2, HTTP 403tests/capture/params-failures.mjs::an_artifact_prefix_outside_the_root_is_refused
steps-not-arrayreading the {action} parameters{action} requires steps as an array.steps: {value}send steps as a list of { "op": ..., "value": ... }, or leave it outrefused, exit 2, HTTP 403tests/capture/params-failures.mjs::steps_that_are_not_a_list_are_refused
step-op-unknownreading the {action} parameters{action} rejects step op {op}: op must be one of {ops}.op: {op}send each step with an op of {ops}refused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_step_of_an_unknown_op_is_refused
step-value-missingreading the {action} parameters{action} rejects step op {op} without a value: {name} requires a value.value: {value}send the step with the selector, key or address its op acts on as valuerefused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_click_step_without_a_selector_is_refused
axis-unknownreading the {action} parameters{action} rejects axis {value}: axis must be one of {axes}.axis: {value}send axis as one of {axes}refused, exit 2, HTTP 403tests/capture/params-failures.mjs::an_unknown_axis_is_refused
record-seconds-invalidreading the {action} parameters{action} rejects record_seconds {value}: record_seconds must be a number of seconds, zero or more.record_seconds: {value}send record_seconds as 0 for stills, or the seconds of video to recordrefused, exit 2, HTTP 403tests/capture/params-failures.mjs::negative_record_seconds_are_refused
full-page-invalidreading the {action} parameters{action} rejects full_page {value}: full_page must be true or false.full_page: {value}send full_page as true or false, or leave it outrefused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_full_page_that_is_not_a_boolean_is_refused
plan-missingreading the plan the {action} trajectory was handed{name} is required: the trajectory runs only from the plan dispatch wrote{name}: {value}start the action through the worker (POST /run), which writes {name}; a hand run sets it to the JSON parametersrefused, exit 2, HTTP 403tests/capture/params-failures.mjs::a_capture_run_without_its_plan_is_refused

release#

43 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
document-unreadablereading the {document} at {path}the file is not there or this user cannot read it: a path naming another directory, or a checkout that lacks it{answer}name the file that holds the {document}, or run in the checkout that carries itnot_found, exit 1, HTTP 404tests/release/documents/document-failures.mjs::a_document_that_is_not_there_is_named
document-not-jsonreading the {document} at {path}the file is there but does not hold one JSON document{answer}write the {document} as the JSON the release pipeline produced, or name the file that holds itconfig, exit 1, HTTP 503tests/release/documents/document-failures.mjs::a_document_that_is_not_json_is_named
document-unwritablewriting the {document} to {path}the directory is not there or this user cannot write to it, so the document stays as it was{answer}name a path in a directory this user can write, then run againconfig, exit 1, HTTP 503tests/release/documents/document-failures.mjs::a_document_that_cannot_be_written_is_named
surface-reader-unavailableloading the TypeScript compiler the surface is read withthe surface is read from a checkout through its development dependencies, and this install carries no TypeScript compiler: an installed weles, or a checkout before npm ci{answer}run weles release surface --root <checkout> from a Weles checkout after npm ciconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_without_the_typescript_compiler_names_it
surface-tsconfig-missingfinding the TypeScript program of {root}the directory holds no tsconfig.json, so it is no Weles checkout and its program cannot be readno file {path}name a Weles checkout with --root, or run in oneconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_directory_without_tsconfig_names_it
surface-tsconfig-invalidreading the TypeScript program of {root}TypeScript refuses its tsconfig.json in the words below{path}: {answer}correct the tsconfig.json TypeScript names, then run againconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_checkout_whose_tsconfig_is_broken_names_it
surface-source-unparsedreading {what} out of the program of {root}the program TypeScript built does not hold the file the surface is read from: it is not there, or tsconfig.json leaves it outnot parsed: {path}run in a complete Weles checkout, or include the file in tsconfig.jsonconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_checkout_without_its_library_entry_names_it
surface-index-unexportedreading the exports of src/index.ts in {root}src/index.ts is not a module: it exports nothing, so the library publishes nothing a reader can list{path} has no module symbolexport the library from src/index.ts, then run againconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_library_entry_that_exports_nothing_names_it
surface-bin-missingreading the commands package.json publishes in {root}package.json has no bin map, so no command of the package is knownbin: {value}restore the bin map of package.json, then run againconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_package_without_commands_names_it
surface-command-not-literalreading the CliCommand union of {path}a member of CliCommand is not a string literal, so the command it stands for has no name the surface can listmember: {value}write every member of CliCommand as a string literalconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_cli_whose_command_is_no_literal_names_it
surface-nothing-resolvedreading the {what} of {root}the scan found none, and a build that publishes no {what} is a scan that broke: the declaration it reads moved or was renamed{path}restore the declaration the reader names (CliCommand in src/cli.ts, ToolDefinition[] lists in src/mcp, "METHOD /path" literals in the worker API server), or teach src/release/surface/published.mjs where it movedconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_cli_without_commands_names_it
surface-tool-not-literalreading the MCP tools of {path}a tool of a ToolDefinition[] list is not an object literal with a string literal name, so the tool has no name the surface can list{value}declare every MCP tool as an object literal with name: "<tool>"config, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_an_mcp_tool_without_a_literal_name_names_it
surface-schemas-nonereading the API schemas of release/policy/compatibility-policy.json in {root}the compatibility policy lists no API schema in api.supportedSchemas, so the release would claim noneapi.supportedSchemas: {value}list the API schemas this release serves in api.supportedSchemasconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_policy_without_schemas_names_it
surface-version-undeclaredreading the released version of release/version-change.json in {root}the version declaration states no current version, so the surface cannot say which release it iscurrent: {value}adopt what Stado publishes (scripts/release/version/adopt-published.mjs), which writes currentconfig, exit 1, HTTP 503tests/release/surface-failures.mjs::surface_of_a_checkout_without_its_released_version_names_it
declaration-schema-unsupportedreading the version declarationits schema is not weles.version-change.v1, the one the gate readsschema: {value}write release/version-change.json as weles.version-change.v1 (scripts/release/version/declare-candidate.mjs writes one)config, exit 1, HTTP 503tests/release/deploying/enforce-failures.mjs::enforce_of_a_declaration_of_another_schema_names_it
declaration-field-invalidreading {field} of the version declaration{field} must be {shape}{field}: {value}state {field} as {shape} in release/version-change.jsonconfig, exit 1, HTTP 503tests/release/deploying/enforce-failures.mjs::enforce_of_a_declaration_without_its_reason_names_it
baseline-disagreesholding the released baseline against the version declarationthe baseline records another release than the declaration names as current, so one of them was not adopted from what Stado publishesbaseline {baseline}, declaration current {current}adopt what Stado publishes (scripts/release/version/adopt-published.mjs), which writes bothrefused, exit 1, HTTP 403tests/release/deploying/enforce-failures.mjs::enforce_of_a_baseline_another_release_names_it
decision-disagreesholding AutoVersion's decision against the version declarationAutoVersion judged from another current release than the declaration namesAutoVersion current {decided}, declaration current {current}run AutoVersion against the baseline the declaration names, or adopt the published release firstrefused, exit 1, HTTP 403tests/release/deploying/enforce-failures.mjs::enforce_of_a_decision_from_another_release_names_it
package-disagreesholding package.json against the version declarationthe package version is not the candidate the declaration namespackage {version}, declaration candidate {candidate}set the candidate in both (npm version <candidate> after declare-candidate.mjs), then run againrefused, exit 1, HTTP 403tests/release/deploying/enforce-failures.mjs::enforce_of_a_package_of_another_version_names_it
decision-field-invalidreading {field} of AutoVersion's decision{field} must be {shape}{field}: {value}run AutoVersion again and pass the decision it writesconfig, exit 1, HTTP 503tests/release/deploying/enforce-failures.mjs::enforce_of_a_decision_of_an_unknown_change_names_it
breaking-not-escalatedholding a declared breaking change against AutoVersionthe declaration says the change breaks callers and AutoVersion found no published surface removeddeclared breaking, AutoVersion change {change}remove the surface the change breaks, or declare it not breaking with its reasonrefused, exit 1, HTTP 403tests/release/deploying/enforce-failures.mjs::enforce_of_a_breaking_change_autoversion_did_not_find_names_it
version-keptholding the package version against a changed surfacethe published surface changed and the package keeps the released version, so callers could not tell the releases apartpackage remains {current}; AutoVersion requires {required}declare {required} as candidate and set it in package.jsonrefused, exit 1, HTTP 403tests/release/deploying/enforce-failures.mjs::enforce_of_a_changed_surface_under_the_same_version_names_it
version-not-requiredholding the declared candidate against AutoVersionthe candidate is not the version the surface change requires: too small a step hides a change, too large one claims a break that is not theredeclared {candidate}, AutoVersion requires {required}declare {required} as candidate and set it in package.jsonrefused, exit 1, HTTP 403tests/release/deploying/enforce-failures.mjs::enforce_of_a_candidate_autoversion_does_not_require_names_it
manifest-schema-unsupportedreading the candidate deployment manifest {path}its schema is not weles.deployment.v2, the contract a release is judged byschema: {value}write the manifest as weles.deployment.v2config, exit 1, HTTP 503tests/release/validate-failures.mjs::validate_of_a_manifest_of_another_schema_names_it
manifest-properties-mismatchreading {field} of the candidate deployment manifest {path}{field} must hold exactly the properties the contract names, no fewer and no othersmissing [{missing}], unexpected [{unexpected}]write {field} with exactly the properties weles.deployment.v2 namesconfig, exit 1, HTTP 503tests/release/validate-failures.mjs::validate_of_a_manifest_with_a_property_too_many_names_it
manifest-field-invalidreading {field} of the candidate deployment manifest {path}{field} must be {shape}{field}: {value}write {field} as {shape}config, exit 1, HTTP 503tests/release/validate-failures.mjs::validate_of_a_manifest_whose_revision_is_short_names_it
manifest-revision-mismatchholding the candidate manifest against the revision releasedthe manifest was made for another source revision than the release is cut frommanifest sourceRevision {manifest}, release target {target}make the manifest from the revision the release is for, or release the revision it namesrefused, exit 1, HTTP 403tests/release/validate-failures.mjs::validate_of_a_manifest_for_another_revision_names_it
candidate-tag-mismatchholding the candidate tag against the manifesta candidate tag names the manifest deployment and an abbreviation of the released revision, and this one does nottag {tag}; expected {prefix}<abbreviation of {revision}>cut the tag as {prefix}<abbreviation of {revision}>refused, exit 1, HTTP 403tests/release/validate-failures.mjs::validate_with_a_tag_of_another_deployment_names_it
adopt-released-invalidreading the released version to adoptit is not a SemVer version, so no baseline can be ordered against itreleased: {value}give --released the version the release was published as, such as 0.8.0refused, exit 2, HTTP 403tests/release/deploying/adopt-failures.mjs::adopting_a_release_that_is_no_version_is_refused
adopt-surface-emptyreading the published surface {path}the document lists no surface, and a release that published nothing is a surface that was not readsurface: {value}give --published-surface the released-surface.json the published build's runtime payload carriesconfig, exit 1, HTTP 503tests/release/deploying/adopt-failures.mjs::adopting_a_surface_that_lists_nothing_is_refused
adopt-baseline-unversionedreading the version the recorded baseline {path} namesthe recorded baseline states no SemVer version, so nothing can say whether this release moves back from itversion: {value}restore the baseline from the repository, or pass --correcting <its version> to replace a claim that was never publishedconfig, exit 1, HTTP 503tests/release/deploying/adopt-failures.mjs::adopting_over_a_baseline_without_a_version_is_refused
adopt-moves-backwardsrecording {released} as published over {recorded}the baseline would move backwards, which lets a surface that was removed pass as newly addedrecorded {recorded}, released {released}adopt the newer release, or pass --correcting {recorded} to state that {recorded} was never publishedrefused, exit 1, HTTP 403tests/release/deploying/adopt-failures.mjs::adopting_an_older_release_over_a_newer_baseline_is_refused
adopt-platform-missingreading the command line of adopt-published.mjs--platform is required: it reads the published archive of one platform, and none was namedgiven: {given}run node scripts/release/version/adopt-published.mjs --platform <platform> [--root <checkout>]refused, exit 2, HTTP 403tests/release/deploying/adopt-failures.mjs::adopting_the_published_release_without_a_platform_is_refused
adopt-product-unnamedreading the product and runtime payload .wisent-release.json names in {root}the release manifest names no product or no runtime.binary, so there is no release to ask Stado for and no payload to read the surface fromproduct: {product}, runtime.binary: {payload}run in a Weles checkout, or name one with --rootconfig, exit 1, HTTP 503tests/release/deploying/adopt-failures.mjs::adopting_from_a_manifest_naming_no_payload_is_refused
adopt-targets-unstatedreading `stado release status {product} --json`Stado answered a document without the targets list its release status carries: a Stado older than this Welestargets: {value}upgrade Stado to the minimum_stado_version this Weles release names, then run againconfig, exit 1, HTTP 503tests/release/deploying/adopt-failures.mjs::adopting_from_a_status_without_targets_names_it
adopt-nothing-publishedfinding the {platform} release Stado serves of {product}no target Stado rolls {product} out to desires a {platform} releasetargets: {targets}publish a {platform} release first (stado release submit), or name a platform it was published fornot_found, exit 1, HTTP 404tests/release/deploying/adopt-failures.mjs::adopting_a_platform_nothing_was_published_for_names_it
adopt-rollout-unsettledfinding the one release Stado serves of {product}the targets desire different releases, so a rollout is still moving and no single release is the published one{named}wait until stado release status {product} names one desired release on every target, then run againrefused, exit 1, HTTP 403tests/release/deploying/adopt-failures.mjs::adopting_during_a_rollout_names_each_release
adopt-archive-unreadabletaking {member} out of {archive}tar could not extract it: the archive Stado fetched does not carry the runtime payload or its released-surface.jsontar exited {status}: {answer}fetch the release again with stado release fetch; a release whose payload lacks released-surface.json was built before the surface was carried, and is adopted with weles release adopt from its sourceconfig, exit 1, HTTP 503tests/release/deploying/adopt-failures.mjs::adopting_an_archive_without_its_surface_names_it
deployment-identity-partialreading the release identity this worker was deployed withthe release identity is stated in part: {set} of {total} settings hold a value, and once any setting only a deployment states holds one, an identity is stated wholeunset: {unset}start the worker through its release launcher, which states every WELES_* release setting together, or unset the deployment's own settings (version, revision, digests, deployment id, ring, claims switch, API schemas) to run without oneconfig, exit 1, HTTP 500tests/release/deploying/deployment-failures.mjs::a_partly_stated_release_identity_names_the_unset_settings
deployment-ring-unknownreading the release identity this worker was deployed withWELES_DEPLOYMENT_RING is {ring}, which is not a release ringrings: {rings}set WELES_DEPLOYMENT_RING to one of {rings}; start the worker through its release launcher, which states every WELES_* release setting togetherconfig, exit 1, HTTP 500tests/release/deploying/deployment-failures.mjs::a_deployment_ring_of_no_release_names_the_rings
deployment-claims-invalidreading the release identity this worker was deployed withWELES_CLAIMS_ENABLED is {value}, which is not a claims switchswitches: {switches}set WELES_CLAIMS_ENABLED to one of {switches}; start the worker through its release launcher, which states every WELES_* release setting togetherconfig, exit 1, HTTP 500tests/release/deploying/deployment-failures.mjs::a_claims_switch_that_is_none_names_the_switches
deployment-ring-claimsreading the release identity this worker was deployed withrelease ring {ring} {claims} queued work, but WELES_CLAIMS_ENABLED is {value}ring {ring}; WELES_CLAIMS_ENABLED {value}set WELES_CLAIMS_ENABLED to {expected} for ring {ring}; start the worker through its release launcher, which states every WELES_* release setting togetherconfig, exit 1, HTTP 500tests/release/deploying/deployment-failures.mjs::a_claims_switch_against_its_ring_names_both
deployment-instance-unnamednaming this worker instanceneither WELES_INSTANCE_ID nor INSTANCE_ID is set, and this machine reports no host name, so the id would name no machinehost name: empty; process {pid}set WELES_INSTANCE_ID in the worker's environment, or give the machine a host name (`hostname` prints it)config, exit 1, HTTP 500tests/release/deploying/deployment-failures.mjs::an_instance_on_a_nameless_host_is_refused

objects#

21 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
token-repeatedreading WELES_STADO_OBJECT_API_TOKEN, the bearer of the Stado object APIit holds the same value as {sibling}: each service Weles reaches has a bearer of its own, so one leaked token opens one service onlyWELES_STADO_OBJECT_API_TOKEN equals {sibling}state the object API bearer from its own item (`stado credentials get --role weles-object-api --field token`) and {sibling} from its own, then start againconfig, exit 1, HTTP 503tests/artifacts/object-failures.mjs::an_object_token_repeating_another_bearer_is_refused
namespace-unknownnaming the private object {key}Weles writes objects only into the namespaces it declares, and {namespace} is not onenamespace: {namespace}; declared: {namespaces}write into one of {namespaces}; a new namespace is declared in src/worker/objects/stado-object.ts firstrefused, exit 1, HTTP 403tests/artifacts/object-failures.mjs::an_object_in_an_undeclared_namespace_is_refused
key-emptynaming a private object in {namespace}the object key is empty, so it names no objectkey: ""name the object by its path under the namespace, such as recordings/<run>/<file>refused, exit 1, HTTP 403tests/artifacts/object-failures.mjs::an_object_without_a_key_is_refused
key-characternaming the private object {key} in {namespace}the key holds {character}, which a stado:// address cannot carry unescaped (a backslash, ?, # or a control character)key: {key}rename the file or step the key comes from without {character}refused, exit 1, HTTP 403tests/artifacts/object-failures.mjs::an_object_key_holding_a_reserved_character_is_refused
key-segmentnaming the private object {key} in {namespace}segment {index} of the key is {segment}: a key is relative and every segment names one step down (no empty segment, no . or ..)key: {key}name the object by a relative path without empty, . or .. segments and without a leading or trailing /refused, exit 1, HTTP 403tests/artifacts/object-failures.mjs::an_object_key_with_a_dot_segment_is_refused
api-unreachable{method} {uri} at the Stado object API {origin}the object API did not answer: nothing listens at {origin}, the forward to it is down, or the network refused the connection{answer}`stado service directory connect stado-object-api --consumer weles` shows the route this host reaches it at; once it answers, the run's artifacts are uploaded again when the task is retainedinfra_down, exit 69, HTTP 503, retryabletests/artifacts/object-failures.mjs::an_object_put_to_a_closed_port_names_the_origin
answer-unreadreading the answer of {method} {uri}the object API answered HTTP {status} and the connection broke before its body was read{answer}ask again; if it repeats, `stado service directory connect stado-object-api --consumer weles` shows the route this host reaches it at and check the forward's logsinfra_down, exit 69, HTTP 503, retryabletests/artifacts/object-failures.mjs::an_object_answer_cut_off_is_named
bearer-refused{method} {uri}the object API refused WELES_STADO_OBJECT_API_TOKEN (HTTP {status}): it is not the bearer the API issued to weles, or it was revokedHTTP {status}: {body}state WELES_STADO_OBJECT_API_TOKEN from `stado credentials get --role weles-object-api --field token` and start the worker againauth, exit 1, HTTP 401tests/artifacts/object-failures.mjs::an_object_put_with_a_bearer_stado_refuses_is_named
api-failing{method} {uri}the object API failed on its side (HTTP {status}), so the object was not {done}HTTP {status}: {body}ask again later; if it repeats, `stado service logs stado-object-api` shows why the API failsinfra_down, exit 69, HTTP 503, retryabletests/artifacts/object-failures.mjs::an_object_api_failing_on_its_side_is_named
request-refused{method} {uri}the object API refused the request (HTTP {status}): its answer says whyHTTP {status}: {body}correct what the answer names (the object's size, type or address) and ask again; `stado service logs stado-object-api` shows the API's side of the refusalrefused, exit 1, HTTP 403tests/artifacts/object-failures.mjs::an_object_request_stado_refuses_quotes_its_answer
object-absentreading back {uri}the object API holds no object at that address: it was never acknowledged, or it was removed after its locator was publishedHTTP {status}: {body}upload the run's artifacts again (the task's retention does it), then read it backnot_found, exit 1, HTTP 404tests/artifacts/object-failures.mjs::an_object_readback_of_an_absent_object_is_named
receipt-not-jsonreading the storage receipt of PUT {uri}the object API answered HTTP {status} with a body that is not JSON, so nothing acknowledges the object was stored{bytes} bytes beginning {body}; parser: {answer}`stado service directory connect stado-object-api --consumer weles` shows the route this host reaches it at; a page that is no receipt means the route reaches something other than the object APIconfig, exit 1, HTTP 503tests/artifacts/object-failures.mjs::an_object_receipt_that_is_not_json_is_named
receipt-invalidreading the storage receipt of PUT {uri}the receipt does not acknowledge exactly these bytes at this address: its {member} is {found} where {expected} was sentreceipt: {receipt}compare the object API's version with the stado.storage-put-receipt.v1 Weles reads; the object is not published until a receipt acknowledges itconfig, exit 1, HTTP 503tests/artifacts/object-failures.mjs::an_object_receipt_of_other_bytes_is_named
readback-limit-invalidreading back {uri}the byte limit of a readback is a whole number above zero, and {limit} is notlimit: {limit}pass the size the retention manifest recorded for the object as the limitrefused, exit 1, HTTP 403tests/artifacts/object-failures.mjs::an_object_readback_without_a_byte_limit_is_refused
readback-uri-invalidreading back {uri}the address is {why}, so it names no private object Weles wroteuri: {uri}read back the stado://<namespace>/<key> URI a storage receipt acknowledged, unchangedrefused, exit 1, HTTP 403tests/artifacts/object-failures.mjs::an_object_readback_of_an_address_that_is_no_object_is_refused
readback-stream-brokenreading back {uri}the object API's answer broke off after {chunks} chunk(s) and {bytes} bytes, so the object cannot be compared{answer}read it back again; if it repeats, `stado service directory connect stado-object-api --consumer weles` shows the route this host reaches it atinfra_down, exit 69, HTTP 503, retryabletests/artifacts/object-failures.mjs::an_object_readback_cut_off_is_named
readback-too-largereading back {uri}the object holds more than the {limit} bytes it was recorded with: something else wrote to that address after the receiptmore than {limit} bytes streamed ({bytes} read before stopping)upload the run's artifacts again so the address holds what its receipt acknowledged, and find what else writes thereconfig, exit 1, HTTP 503tests/artifacts/object-failures.mjs::an_object_larger_than_its_record_is_named
tree-unreadablelisting the recordings of run {run}Artifact directory read failed for {directory}: the worker user cannot list it ({code}), or it is not a directory{answer}give the worker's user read and search access to {directory} (`ls -ld {directory}` shows its owner and mode), or retain the task only once its run has recorded into itconfig, exit 1, HTTP 503tests/artifacts/uploads/upload-failures.mjs::a_recordings_directory_the_worker_cannot_list_names_it
file-unreadablereading {file} of run {run} to store itthe worker user cannot read the file ({code}): its mode changed, or it was removed while the run was uploaded{answer}; {stored} of {count} file(s) were already storedgive the worker's user read access to {file} (`ls -l {file}`), then retain the task again; objects already stored are acknowledged again without being rewrittenconfig, exit 1, HTTP 503tests/artifacts/uploads/upload-failures.mjs::a_recording_the_worker_cannot_read_names_it
proof-unstatablewriting the upload proof of run {run}Artifact proof stat failed for {file}: every object was acknowledged, but the file can no longer be examined ({code}), so its size cannot enter the proof{answer}find what removed or locked {file} after it was stored, restore it, then retain the task again; without a proof the run reads as not mirroredconfig, exit 1, HTTP 503tests/artifacts/uploads/upload-failures.mjs::a_recording_removed_before_the_proof_names_it
proof-unwritablewriting the upload proof of run {run}every object was acknowledged, but {file} cannot be written ({code}): the run directory is read-only to the worker user, or its disk is full{answer}give the worker's user write access to {directory} and free space on its disk, then retain the task again; without a proof the run reads as not mirroredconfig, exit 1, HTTP 503tests/artifacts/uploads/upload-failures.mjs::a_run_directory_refusing_the_proof_names_it

artifacts#

41 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
locators-not-objectchecking a run's artifact locatorsthe artifacts are not one object of locator lists keyed by kindartifacts: {found}pass the locators uploadArtifacts answered for the run, unchanged: an object with exactly the keys {kinds}refused, exit 1, HTTP 400tests/artifacts/delivery/signing-failures.mjs::locators_that_are_no_object_are_refused
locators-kindschecking a run's artifact locatorsthe artifacts hold the kinds {found} where exactly {kinds} are declared (src/worker/artifacts/artifact-kinds.json)missing: {missing}; not declared: {extra}pass the locators uploadArtifacts answered for the run, unchanged: one list for each of {kinds}, empty where the run recorded nonerefused, exit 1, HTTP 400tests/artifacts/delivery/signing-failures.mjs::locators_of_other_kinds_are_refused
locators-kind-not-listchecking a run's artifact locatorsartifacts.{kind} is not a list of locatorsartifacts.{kind}: {found}pass the locators uploadArtifacts answered for the run, unchanged: artifacts.{kind} as a list, empty when the run recorded none of that kindrefused, exit 1, HTTP 400tests/artifacts/delivery/signing-failures.mjs::a_kind_that_is_no_list_is_refused
locator-not-textchecking a run's artifact locators{place} is not text, or has blanks around it: a locator is stado://weles/recordings/<run uuid>/<path>, with a lowercase run UUID and a path of plain segments{place}: {found}pass the locators uploadArtifacts answered for the run, unchangedrefused, exit 1, HTTP 400tests/artifacts/delivery/signing-failures.mjs::a_locator_that_is_no_text_is_refused
locator-namespacechecking a run's artifact locators{place} is not under stado://weles/recordings/: a locator is stado://weles/recordings/<run uuid>/<path>, with a lowercase run UUID and a path of plain segments{place}: {found}pass the locators uploadArtifacts answered for the run, unchangedrefused, exit 1, HTTP 400tests/artifacts/delivery/signing-failures.mjs::a_locator_outside_the_recordings_is_refused
locator-characterchecking a run's artifact locators{place} holds {character}, which could leave the recordings path: a locator is stado://weles/recordings/<run uuid>/<path>, with a lowercase run UUID and a path of plain segments{place}: {found}pass the locators uploadArtifacts answered for the run, unchangedrefused, exit 1, HTTP 400tests/artifacts/delivery/signing-failures.mjs::a_locator_holding_a_reserved_character_is_refused
locator-pathchecking a run's artifact locators{place} has no file under its run, or an empty, . or .. segment: a locator is stado://weles/recordings/<run uuid>/<path>, with a lowercase run UUID and a path of plain segments{place}: {found}pass the locators uploadArtifacts answered for the run, unchangedrefused, exit 1, HTTP 400tests/artifacts/delivery/signing-failures.mjs::a_locator_with_a_dot_segment_is_refused
locator-runchecking a run's artifact locators{place} names the run {run}, which is not a lowercase UUID: a locator is stado://weles/recordings/<run uuid>/<path>, with a lowercase run UUID and a path of plain segments{place}: {found}pass the locators uploadArtifacts answered for the run, unchangedrefused, exit 1, HTTP 400tests/artifacts/delivery/signing-failures.mjs::a_locator_of_no_run_uuid_is_refused
delivery-unreachableWeles artifact delivery POST {endpoint}the artifact delivery service did not answer: nothing listens at {origin}, or the network refused the connection{answer}check WELES_ARTIFACT_DELIVERY_URL names the delivery service that runs for this deployment, and ask again once it answersinfra_down, exit 69, HTTP 503, retryabletests/artifacts/delivery/signing-failures.mjs::signing_at_a_closed_port_names_the_service
delivery-answer-unreadWeles artifact delivery POST {endpoint}the delivery service answered HTTP {status} and the connection broke before its body was read{answer}ask again; if it repeats, read the delivery service's log for the requestinfra_down, exit 69, HTTP 503, retryabletests/artifacts/delivery/signing-failures.mjs::a_signing_answer_cut_off_is_named
delivery-answer-not-jsonWeles artifact delivery POST {endpoint}the delivery service answered HTTP {status} with a body that is not JSON: WELES_ARTIFACT_DELIVERY_URL reaches something other than the delivery service{bytes} bytes beginning {body}; parser: {answer}set WELES_ARTIFACT_DELIVERY_URL to the delivery service's origin; a page that is no JSON is another serverconfig, exit 1, HTTP 503tests/artifacts/delivery/signing-failures.mjs::a_signing_answer_that_is_not_json_is_named
delivery-refusedWeles artifact delivery POST {endpoint}the delivery service refused to sign (HTTP {status}): {detail}HTTP {status}; its cause {served}; its fix: {served_fix}; body: {body}correct what the service names (a 401 is WELES_ARTIFACT_DELIVERY_TOKEN, a 400 or 403 the locators) and ask again; `weles errors show artifacts` lists the service's causesrefused, exit 1, HTTP 403tests/artifacts/delivery/signing-failures.mjs::a_signing_refusal_quotes_the_service
delivery-answer-envelopeWeles artifact delivery POST {endpoint}the answer is not an object holding expires_at as text and artifacts as an object, so it signs nothinganswer: {found}compare the delivery service's release with this Weles release; it answers an object of expires_at (an ISO time) and artifacts (one list of signed URLs per kind)config, exit 1, HTTP 503tests/artifacts/delivery/signing-failures.mjs::a_signed_answer_without_its_envelope_is_named
delivery-answer-expiryWeles artifact delivery POST {endpoint}expires_at {found} is not a time after now ({now}), so every URL it signs is already dead or undatedexpires_at: {found}check the delivery host's clock against this host's, then compare the delivery service's release with this Weles releaseconfig, exit 1, HTTP 503tests/artifacts/delivery/signing-failures.mjs::a_signed_answer_already_expired_is_named
delivery-answer-countWeles artifact delivery POST {endpoint}artifacts.{kind} holds {found} where {expected} locator(s) of that kind were sent, so a URL cannot be matched to the locator it signsartifacts.{kind}: {answer}compare the delivery service's release with this Weles releaseconfig, exit 1, HTTP 503tests/artifacts/delivery/signing-failures.mjs::a_signed_answer_dropping_a_locator_is_named
delivery-answer-urlWeles artifact delivery POST {endpoint}artifacts.{kind}[{index}] {why}, so it is not the signed URL of {locator}artifacts.{kind}[{index}]: {found}compare the delivery service's release with this Weles release; a signed URL is {origin}/v1/artifacts/object?uri=<locator>&expires=<epoch seconds>&signature=<hex>config, exit 1, HTTP 503tests/artifacts/delivery/signing-failures.mjs::a_signed_answer_with_a_foreign_url_is_named
serve-host-invalidreading the artifact delivery service's configurationWELES_ARTIFACT_DELIVERY_HOST holds {character}, so it names a path rather than the address the service listens onWELES_ARTIFACT_DELIVERY_HOST: {host}set WELES_ARTIFACT_DELIVERY_HOST to a host name or IP address (127.0.0.1 behind a forward) and start the service againconfig, exit 1, HTTP 503tests/artifacts/delivery/delivery-server-failures.mjs::a_listen_address_that_is_a_path_is_refused
serve-credentials-repeatedreading the artifact delivery service's configuration{first} and {second} hold the same value: the signing bearer, the signing secret, the Stado object bearer and the subscriptions bearer are each its own, so one leaked value opens one door only{first} equals {second}; the values are not showngive {second} a value of its own (`stado credentials get --role <its role> --field token` answers each), and start the service againconfig, exit 1, HTTP 503tests/artifacts/delivery/delivery-server-failures.mjs::credentials_that_repeat_each_other_are_refused
serve-route-unknownserving {method} {path}the service answers only {routes}, and {method} {path} with the query {query} is none of themmethod {method}; path {path}; query {query}ask one of GET /v1/subscriptions (bearer OKO_WELES_SUBSCRIPTIONS_TOKEN), POST /v1/artifacts/sign (bearer WELES_ARTIFACT_DELIVERY_TOKEN) and GET /v1/artifacts/object with the uri, expires and signature a signing answerednot_found, exit 1, HTTP 404tests/artifacts/delivery/delivery-server-failures.mjs::a_request_for_no_route_names_the_routes
serve-bearer-missingserving {method} {path}the request carries {found} where the route needs Authorization: Bearer <{setting}>Authorization: {found}send the request with Authorization: Bearer and the value of {setting} the service was started withauth, exit 1, HTTP 401tests/artifacts/delivery/delivery-server-failures.mjs::a_request_without_its_bearer_is_refused
serve-bearer-wrongserving {method} {path}the bearer the request carries ({length} characters) is not the value of {setting} the service was started witha Bearer of {length} characters; the value is not shownsend the current value of {setting}; when it was rotated, start the service again with the new oneauth, exit 1, HTTP 401tests/artifacts/delivery/delivery-server-failures.mjs::a_request_with_another_bearer_is_refused
serve-media-type-missingserving {method} {path}the request states no Content-Type, and the locators to sign are read only from a JSON bodyContent-Type: absentsend the locators with Content-Type: application/jsonrefused, exit 1, HTTP 415tests/artifacts/delivery/delivery-server-failures.mjs::a_signing_request_stating_no_type_is_refused
serve-media-type-wrongserving {method} {path}the request states the type {found}, and the locators to sign are read only from application/jsonContent-Type: {found}send the locators with Content-Type: application/jsonrefused, exit 1, HTTP 415tests/artifacts/delivery/delivery-server-failures.mjs::a_signing_request_of_another_type_is_refused
serve-body-unreadserving {method} {path}the connection broke after {bytes} bytes of the request body, before the whole body arrived{answer}send the request again; a body that never arrives whole is the caller or the network between it and the serviceinfra_down, exit 69, HTTP 400, retryabletests/artifacts/delivery/delivery-server-failures.mjs::a_signing_body_cut_off_is_named
serve-body-not-jsonserving {method} {path}the request body is not JSON, so it holds no locators to sign{bytes} bytes beginning {body}; parser: {answer}send {"artifacts": {<kind>: [<locator>, ...]}} as the body, one list per declared kindrefused, exit 1, HTTP 400tests/artifacts/delivery/delivery-server-failures.mjs::a_signing_body_that_is_not_json_is_refused
serve-body-fieldsserving {method} {path}the request body holds {found} where it holds exactly one member, artifactsbody: {body}send {"artifacts": {<kind>: [<locator>, ...]}} and nothing beside itrefused, exit 1, HTTP 400tests/artifacts/delivery/delivery-server-failures.mjs::a_signing_body_beside_its_artifacts_is_refused
serve-signature-malformedserving {method} {path}the object URL does not carry exactly uri, expires (whole epoch seconds) and a hex signature: {why}query: {query}have the locator signed again (POST /v1/artifacts/sign) and fetch the URL that answer holds, unchangedrefused, exit 1, HTTP 403tests/artifacts/delivery/delivery-server-failures.mjs::an_object_url_without_its_signature_is_refused
serve-url-expiredserving {method} {path}the signed URL expired at {expires} ({expiry}), {ago} seconds before this requestexpires {expires}; now {now}have the locator signed again (POST /v1/artifacts/sign) and fetch the URL that answer holds, unchangedrefused, exit 1, HTTP 403tests/artifacts/delivery/delivery-server-failures.mjs::an_expired_object_url_is_refused
serve-url-beyond-ttlserving {method} {path}the URL claims to live until {expires}, {ahead} seconds from now, past the {ttl} seconds (WELES_ARTIFACT_URL_TTL_SECONDS) this service signs for: the service never signed itexpires {expires}; now {now}; WELES_ARTIFACT_URL_TTL_SECONDS {ttl}have the locator signed again (POST /v1/artifacts/sign) and fetch the URL that answer holds, unchangedrefused, exit 1, HTTP 403tests/artifacts/delivery/delivery-server-failures.mjs::an_object_url_living_past_the_ttl_is_refused
serve-signature-wrongserving {method} {path}the signature does not sign {uri} until {expires} with WELES_ARTIFACT_SIGNING_SECRET: the URL was changed, or signed with a secret this service no longer holdsuri {uri}; expires {expires}; the signatures are not shownhave the locator signed again (POST /v1/artifacts/sign) and fetch the URL that answer holds, unchangedrefused, exit 1, HTTP 403tests/artifacts/delivery/delivery-server-failures.mjs::an_object_url_whose_signature_was_changed_is_refused
serve-subscriptions-not-listlisting the subscriptions of Weles's service_subscriptions setting in Skarbiecthe setting holds {found} where it holds a list of subscription objectsservice_subscriptions: {found}write the subscription again through the worker's subscription route, so the setting holds one object per subscription with service_name and provider as textconfig, exit 1, HTTP 502tests/artifacts/delivery/delivery-server-failures.mjs::subscriptions_that_are_no_list_are_named
serve-subscription-row-invalidlisting the subscriptions of Weles's service_subscriptions setting in Skarbiecsubscription {index} (id {row_id}) {why}service_subscriptions[{index}]: {row}write the subscription again through the worker's subscription route, so the setting holds one object per subscription with service_name and provider as textconfig, exit 1, HTTP 502tests/artifacts/delivery/delivery-server-failures.mjs::a_subscription_row_of_another_shape_is_named
stream-object-unnamedstreaming {uri} out of the Stado object API {stado}the locator {uri} ends in no object name, so there is no file to offer for downloaduri {uri}sign the locator of a file the run recorded, as uploadArtifacts answered itrefused, exit 1, HTTP 400tests/artifacts/delivery/delivery-server-failures.mjs::an_object_url_naming_no_file_is_refused
stream-stado-unreachablestreaming {uri} out of the Stado object API {stado}the object API did not answer GET {request}: nothing listens at {stado}, the forward to it is down, or the network refused the connection{answer}`stado service directory connect stado-object-api --consumer weles` shows the route this host reaches it at; set STADO_API_URL to it and fetch the URL againinfra_down, exit 69, HTTP 502, retryabletests/artifacts/delivery/delivery-server-failures.mjs::an_object_from_a_stado_that_does_not_answer_names_it
stream-stado-answer-unreadstreaming {uri} out of the Stado object API {stado}the object API answered HTTP {upstream_status} to GET {request} and the connection broke before its body was read{answer}fetch the URL again; if it repeats, `stado service directory connect stado-object-api --consumer weles` shows the route this host reaches it at and check the forward's logsinfra_down, exit 69, HTTP 502, retryabletests/artifacts/delivery/delivery-server-failures.mjs::an_object_answer_stado_cuts_off_is_named
stream-object-absentstreaming {uri} out of the Stado object API {stado}the object API holds no object at {uri}: it was never stored, or it was removed after its locator was signedGET {request}: HTTP {upstream_status}: {upstream_detail}upload the run's artifacts again (the task's retention does it), have the locator signed again and fetch that URLnot_found, exit 1, HTTP 404tests/artifacts/delivery/delivery-server-failures.mjs::an_object_stado_does_not_hold_is_named
stream-stado-bearer-refusedstreaming {uri} out of the Stado object API {stado}the object API refused WELES_STADO_OBJECT_API_TOKEN (HTTP {upstream_status}): it is not the bearer the API issued to weles, or it was revokedGET {request}: HTTP {upstream_status}: {upstream_detail}state WELES_STADO_OBJECT_API_TOKEN from `stado credentials get --role weles-object-api --field token` and start the delivery service againconfig, exit 1, HTTP 502tests/artifacts/delivery/delivery-server-failures.mjs::an_object_stado_refuses_the_bearer_for_is_named
stream-stado-failingstreaming {uri} out of the Stado object API {stado}the object API failed on its side (HTTP {upstream_status}), so the object cannot be deliveredGET {request}: HTTP {upstream_status}: {upstream_detail}fetch the URL again later; if it repeats, `stado service logs stado-object-api` shows why the API failsinfra_down, exit 69, HTTP 502, retryabletests/artifacts/delivery/delivery-server-failures.mjs::an_object_stado_fails_to_read_is_named
stream-stado-refusedstreaming {uri} out of the Stado object API {stado}the object API refused the read (HTTP {upstream_status}) for a reason other than the bearer or a missing object; its answer says whichGET {request}: HTTP {upstream_status}: {upstream_detail}compare the object API's release with the GET /api/object?uri= read this service makes; `stado service logs stado-object-api` shows the API's side of the refusalconfig, exit 1, HTTP 502tests/artifacts/delivery/delivery-server-failures.mjs::an_object_read_stado_refuses_quotes_its_answer
stream-brokenstreaming {uri} out of the Stado object API {stado}the object API's answer broke off after the download began (HTTP {upstream_status} already sent to the downloader), so the download ends short{answer}fetch the URL again; if it repeats, `stado service directory connect stado-object-api --consumer weles` shows the route this host reaches it at and check the forward's logsinfra_down, exit 69, HTTP 503, retryabletests/artifacts/delivery/delivery-server-failures.mjs::an_object_stado_breaks_off_mid_stream_is_named
stream-download-abandonedstreaming {uri} out of the Stado object API {stado}the downloader closed its connection before the object was sent whole: it cancelled, or the network between dropped{answer}fetch the URL again while it lives; the service needs nothing changedinfra_down, exit 69, HTTP 503, retryabletests/artifacts/delivery/delivery-server-failures.mjs::a_download_the_downloader_closes_is_named

credentials#

70 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
bearer-missingadmitting the caller of POST /api/v1/credential-operationsone bearer is required, and the request carries no Authorization headerno Authorization headerask the operator of the calling product for a bearer Skarbiec issues for audience weles with call:weles#credential-operations, and send it as the one Authorization: Bearer lineauth, exit 1, HTTP 401tests/credentials/admission-failures.mjs::a_request_without_a_bearer_is_refused
bearer-repeatedadmitting the caller of POST /api/v1/credential-operationsone bearer is required, and the request carries {count} Authorization lines, so which caller speaks is ambiguous{count} Authorization linessend exactly one Authorization: Bearer lineauth, exit 1, HTTP 401tests/credentials/admission-failures.mjs::a_request_with_two_bearers_is_refused
bearer-malformedadmitting the caller of POST /api/v1/credential-operationsone bearer is required, and the Authorization line is not "Bearer <token>" with a token of no spacesscheme {scheme}, {length} characters after itask the operator of the calling product for a bearer Skarbiec issues for audience weles with call:weles#credential-operations, and send it as the one Authorization: Bearer lineauth, exit 1, HTTP 401tests/credentials/admission-failures.mjs::a_request_whose_authorization_is_no_bearer_is_refused
introspection-token-absentadmitting the caller of POST /api/v1/credential-operationsthe worker holds no token of its own to ask Skarbiec with: {path} does not exist, so no caller can be introspected{path} is absenthave Stado issue the worker's introspection token again (`stado credentials token mint` for consumer weles-credential-admission writes ~/.stado/weles-credential-admission-skarbiec-token, owner-only), then send the request againconfig, exit 1, HTTP 503tests/credentials/admission-failures.mjs::a_worker_without_its_introspection_token_refuses
introspection-token-unsafeadmitting the caller of POST /api/v1/credential-operationsthe worker's introspection token file cannot be used: {reason}{path} {reason} (cause {lower})make {path} a regular file only the worker's account can read (`chmod 600 {path}`), or have Stado issue the worker's introspection token again (`stado credentials token mint` for consumer weles-credential-admission writes ~/.stado/weles-credential-admission-skarbiec-token, owner-only), then send the request againconfig, exit 1, HTTP 503tests/credentials/admission-failures.mjs::an_introspection_token_others_can_read_is_refused
introspection-token-unreadadmitting the caller of POST /api/v1/credential-operationsthe system refused to read the worker's introspection token {path} ({errno}){path}: {errno}; system: {answer}give the worker's account read access to {path} (`ls -l {path}`), or have Stado issue the worker's introspection token again (`stado credentials token mint` for consumer weles-credential-admission writes ~/.stado/weles-credential-admission-skarbiec-token, owner-only), then send the request againconfig, exit 1, HTTP 503tests/credentials/admission-failures.mjs::an_introspection_token_the_worker_cannot_read_is_refused
introspection-token-invalidadmitting the caller of POST /api/v1/credential-operationsthe worker's introspection token {path} is {shape}, and a token is one line of no spaces{path}: {bytes} bytes, {shape}; the value is not shownhave Stado issue the worker's introspection token again (`stado credentials token mint` for consumer weles-credential-admission writes ~/.stado/weles-credential-admission-skarbiec-token, owner-only), then send the request againconfig, exit 1, HTTP 503tests/credentials/admission-failures.mjs::an_introspection_token_holding_spaces_is_refused
skarbiec-route-unresolvedadmitting the caller of POST /api/v1/credential-operationsno Skarbiec is reached to introspect the bearer: the secrets alternative refused ({lower}){answer}{fix}config, exit 1, HTTP 503tests/credentials/admission-failures.mjs::a_worker_whose_stado_names_no_skarbiec_refuses
introspection-unreachedasking Skarbiec at {endpoint} to introspect the bearerSkarbiec token introspection at {endpoint} failed: the connection did not answer ({errno})POST {endpoint}/v1/tokens/introspect: {answer}`stado capabilities resolve secrets --consumer weles --json` names the Skarbiec route; start that Skarbiec or correct its route, then send the request againinfra_down, exit 69, HTTP 503, retryabletests/credentials/authority-failures.mjs::an_introspection_skarbiec_does_not_answer_is_named
introspection-unreadreading what Skarbiec at {endpoint} answered the introspectionSkarbiec token introspection at {endpoint} failed: its HTTP {status} answer is not one bounded JSON object, so it is not Skarbiec's introspectionHTTP {status} {type}; reader: {answer}`stado capabilities resolve secrets --consumer weles --json` names the Skarbiec route; a route reaching something other than Skarbiec is corrected thereinfra_down, exit 69, HTTP 503, retryabletests/credentials/authority-failures.mjs::an_introspection_answer_that_is_not_json_is_named
introspection-refusedasking Skarbiec at {endpoint} to introspect the bearer as weles-credential-admissionSkarbiec refused weles-credential-admission token introspection with HTTP {status}: it does not admit the worker's own tokenPOST {endpoint}/v1/tokens/introspect: HTTP {status}; Skarbiec: {said}{fix}; or have Stado issue the worker's introspection token again (`stado credentials token mint` for consumer weles-credential-admission writes ~/.stado/weles-credential-admission-skarbiec-token, owner-only), then send the request againauth, exit 1, HTTP 503tests/credentials/authority-failures.mjs::an_introspection_skarbiec_refuses_is_named
bearer-inactiveadmitting the caller of POST /api/v1/credential-operationsbearer is not active: Skarbiec answers active {active} for it, so it expired or was revokedSkarbiec at {endpoint}: active {active}, consumer {consumer}ask the operator of the calling product for a bearer Skarbiec issues for audience weles with call:weles#credential-operations, and send it as the one Authorization: Bearer lineauth, exit 1, HTTP 401tests/credentials/authority-failures.mjs::a_bearer_skarbiec_answers_inactive_is_refused
audience-otheradmitting the caller of POST /api/v1/credential-operationsbearer requires audience weles and call:weles#credential-operations, and Skarbiec answers audience {audience}consumer {consumer}, audience {audience}ask the operator of the calling product for a bearer Skarbiec issues for audience weles with call:weles#credential-operations, and send it as the one Authorization: Bearer lineauth, exit 1, HTTP 403tests/credentials/authority-failures.mjs::a_bearer_of_another_audience_is_refused
consumer-unnamedadmitting the caller of POST /api/v1/credential-operationsbearer requires audience weles and call:weles#credential-operations, and Skarbiec names no consumer for it ({consumer}), so no record can say who askedaudience {audience}, consumer {consumer}ask the operator of the calling product for a bearer Skarbiec issues for audience weles with call:weles#credential-operations, and send it as the one Authorization: Bearer lineauth, exit 1, HTTP 403tests/credentials/authority-failures.mjs::a_bearer_naming_no_consumer_is_refused
capability-missingadmitting the caller of POST /api/v1/credential-operationsbearer requires audience weles and call:weles#credential-operations, and the scopes Skarbiec answers do not include itconsumer {consumer}: scopes {scopes}ask the operator of the calling product for a bearer Skarbiec issues for audience weles with call:weles#credential-operations, and send it as the one Authorization: Bearer lineauth, exit 1, HTTP 403tests/credentials/authority-failures.mjs::a_bearer_without_the_credential_scope_is_refused
method-refused{method} /api/v1/credential-operationsthe credential-operations route takes POST only, and the request is {method}method {method}POST the credential-operation request as one JSON objectrefused, exit 2, HTTP 405tests/credentials/admission-failures.mjs::a_credential_route_asked_with_get_is_refused
request-unparsedreading the credential-operation requestcredential request must be one bounded JSON object, and the weles-client reader refused the bodyweles-client reader: {answer}; the request stated Content-Type {contentType} and Content-Length {contentLength}send the request as the weles-client credential request builder writes itrefused, exit 2, HTTP 400tests/credentials/contract-failures.mjs::a_credential_request_that_is_not_json_is_refused
request-invalidreading the credential-operation requestthe request is JSON, and the weles-client validator refused its fieldsweles-client validator: {answer}; request {request}, version {version}, fields {members}; Content-Type {contentType}send the fields the weles-client credential request contract names, as its builder writes themrefused, exit 2, HTTP 400tests/credentials/contract-failures.mjs::a_credential_request_of_another_shape_is_refused
dry-run-refusedchecking credential request {request} as a dry runthe dry run's acquisition refused the request before anything ranacquisition: {answer}correct what the acquisition names, then send the dry run again; nothing was recordedrefused, exit 2, HTTP 400tests/credentials/contract-failures.mjs::a_dry_run_its_acquisition_refuses_is_named
mode-refusedreading the credential-operation requestself-hosted credential admission accepts submit and status, not resumemode {mode} for request {request}send mode submit to start the operation, or status with its action log id to read itrefused, exit 2, HTTP 409tests/credentials/contract-failures.mjs::a_credential_request_to_resume_is_refused
admission-stoppingadmitting credential request {request}Weles is draining credential operations: the worker is shutting down and admits no new one{running} operation(s) still finishingsend the request again once `weles worker status` answers the restarted workerinfra_down, exit 69, HTTP 503, retryabletests/credentials/contract-failures.mjs::a_credential_request_while_the_worker_stops_is_refused
contract-undeclaredmatching credential request {request} ({credential}, provider {provider}) to its declared acquisitionNo acquisition is declared for {credential} (provider {provider}); a managed password is declared in the deployment's managed password declarations, and {source}credential {credential}, provider {provider}; {source}send the item, field and writer the deployment's managed password declaration names (`weles errors show credentials` lists the declared causes); the declaration is the file WELES_MANAGED_PASSWORD_CONTRACTS_FILE namesrefused, exit 1, HTTP 409tests/credentials/contract-failures.mjs::a_credential_no_acquisition_declares_is_refused
contract-unresolvedmatching credential request {request} ({credential}, provider {provider}) to its declared acquisitioncredential item, field, and writer must match the exact Weles acquisition contract, and the definition names secret {secret}, which no credential contract resolvesdefinition secret {secret}send the item, field and writer the deployment's managed password declaration names (`weles errors show credentials` lists the declared causes); the declaration is the file WELES_MANAGED_PASSWORD_CONTRACTS_FILE namesrefused, exit 1, HTTP 409tests/credentials/contract-failures.mjs::a_definition_whose_secret_no_contract_resolves_is_refused
contract-othermatching credential request {request} ({credential}, provider {provider}) to its declared acquisitioncredential item, field, and writer must match the exact Weles acquisition contract, and the request names another {what}requested {requested}; declared {declared}send the item, field and writer the deployment's managed password declaration names (`weles errors show credentials` lists the declared causes); the declaration is the file WELES_MANAGED_PASSWORD_CONTRACTS_FILE namesrefused, exit 1, HTTP 409tests/credentials/contract-failures.mjs::a_credential_of_another_field_or_writer_is_refused
directory-mismatchmatching credential request {request} ({credential}, provider {provider}) to its declared acquisitiondirectory identity must match the requested provider: {why}provider {provider}, directory {directory}name a directory (tenant, principal object and UPN) only for provider microsoft_entra, with directory.provider microsoft_entra; omit it for every other providerrefused, exit 1, HTTP 409tests/credentials/contract-failures.mjs::a_directory_of_another_provider_is_refused
origin-mismatchmatching credential request {request} ({credential}, provider {provider}) to its declared acquisitionsignup origin differs from the registered credential capture originrequested {requested}, registered {declared}send signup_origin {declared}, or nonerefused, exit 1, HTTP 409tests/credentials/contract-failures.mjs::a_credential_of_another_signup_origin_is_refused
store-unmadecreating the credential admission records directory {path}the system refused to create it ({errno}), so no credential operation can be recorded{path}: {errno}; system: {answer}give the account the worker runs as write access to {path}, then `weles worker restart`config, exit 1, HTTP 503tests/credentials/record-failures.mjs::a_records_directory_that_cannot_be_made_is_named
record-unsafereading the record of credential request {request}credential admission record is not an owner-only regular file: {path} {reason}{path}: {reason}move {path} aside (the worker never removes what it did not write) and send the request again; `weles worker status` shows the worker that answersconfig, exit 1, HTTP 503tests/credentials/record-failures.mjs::a_record_others_can_read_is_refused
record-unreadreading the record of credential request {request}the system refused to {step} {path} ({errno}){path}: {errno}; system: {answer}give the account the worker runs as read access to {path} (`ls -l {path}`), then send the request againconfig, exit 1, HTTP 503tests/credentials/record-failures.mjs::a_record_the_worker_cannot_read_is_named
record-not-jsonreading the record of credential request {request}credential admission record {path} is not one JSON document: the worker writes it whole, so it was truncated or written by something else{path}: {bytes} bytes; parser: {answer}move {path} aside (the worker never removes what it did not write) and send the request again; `weles worker status` shows the worker that answersconfig, exit 1, HTTP 503tests/credentials/record-failures.mjs::a_record_that_is_not_json_is_refused
record-identity-invalidreading the record of credential request {request}credential admission record identity is invalid: {path} holds {what} {found}, not {expected}{path}: {what} {found}move {path} aside (the worker never removes what it did not write) and send the request again; `weles worker status` shows the worker that answersconfig, exit 1, HTTP 503tests/credentials/record-failures.mjs::a_record_of_another_request_is_refused
record-phase-unknownreading the record of credential request {request}credential admission record {path} names the phase {phase}; the phases are {phases}{path}: phase {phase}compare `weles worker version` with the release that wrote it; a record of another release is read by that release, or moved asideconfig, exit 1, HTTP 503tests/credentials/record-failures.mjs::a_record_of_an_unknown_phase_is_refused
request-consumer-otherreading the record of credential request {request}credential request id is already bound to another identity or request: consumer {recorded} admitted it, and {consumer} asksrecorded consumer {recorded}, asking consumer {consumer}read the operation with mode status and its action log id; a new operation needs a new request idrefused, exit 1, HTTP 409tests/credentials/record-failures.mjs::a_request_id_another_consumer_holds_is_refused
request-fingerprint-otherreading the record of credential request {request}credential request id is already bound to another identity or request: the request differs from the one admitted under itrecorded fingerprint {recorded}, this request {fingerprint}read the operation with mode status and its action log id; a new operation needs a new request idrefused, exit 1, HTTP 409tests/credentials/record-failures.mjs::a_request_id_reused_for_another_request_is_refused
status-task-otherreading the record of credential request {request}credential status names another action log: request {request} runs as {recorded}action log asked {asked}, recorded {recorded}ask the status with action_log_id {recorded}refused, exit 1, HTTP 409tests/credentials/record-failures.mjs::a_status_naming_another_action_log_is_refused
request-not-foundreading the record of credential request {request}credential request was not admitted here: no record of it is under {root}no {path}submit the request first, or ask the worker that admitted itnot_found, exit 1, HTTP 404tests/credentials/record-failures.mjs::a_status_of_a_request_never_admitted_is_not_found
record-id-invalidnaming the record of credential request {request}invalid credential request id: it is not 64 hex digits, and the validator admits only those, so this is a defect of the releaserequest id {request}report it with `weles worker version`; nothing was recordedunknown, exit 1, HTTP 500tests/credentials/record-failures.mjs::a_record_of_an_invalid_id_is_named
phase-move-invalidrecording credential operation {request}credential operation {request} cannot move from {from} to {to}; from {from} it moves to {allowed}: a defect of the releasephase {from}, asked {to}report it with `weles worker version` and the record; the record keeps phase {from}unknown, exit 1, HTTP 500tests/credentials/record-failures.mjs::a_phase_move_the_record_does_not_allow_is_named
trajectories-severalqueuing credential operation {request}one credential operation cannot enqueue multiple trajectories, and its acquisition asked for {action} after {first}: a defect of the acquisition catalogfirst {first}, then {action}report it with `weles worker version`; nothing ranunknown, exit 1, HTTP 502tests/credentials/record-failures.mjs::an_acquisition_enqueuing_two_trajectories_is_named
trajectory-nonequeuing credential operation {request}credential acquisition queued no executable trajectory: it answered operation_queued without asking for oneacquisition answered {status}report it with `weles worker version`; nothing ranunknown, exit 1, HTTP 502tests/credentials/record-failures.mjs::an_acquisition_queuing_nothing_is_named
admission-failedadmitting credential operation {request} through its acquisitionthe acquisition refused before any trajectory ran ({lower}){answer}{fix}infra_down, exit 69, HTTP 502, retryabletests/credentials/record-failures.mjs::an_acquisition_that_refuses_settles_the_operation
execution-not-startedstarting credential operation {request}Weles stopped before starting the credential operationthe worker began stopping with the operation queuedsubmit the operation again under a new request id once the worker answersinfra_down, exit 69, HTTP 502, retryabletests/credentials/record-failures.mjs::an_operation_queued_while_the_worker_stops_is_settled
execution-failedrunning trajectory {action} for credential operation {request}the run failed before it answered ({lower}){answer}{fix}infra_down, exit 69, HTTP 502, retryabletests/credentials/record-failures.mjs::an_operation_whose_run_fails_is_settled
execution-interruptedanswering credential operation {request}Weles {when} before recording a final credential result; the operation was not replayedphase {phase}, no executor for it hereread the provider side for what the run changed, then submit a new operation under a new request idinfra_down, exit 69, HTTP 502, retryabletests/credentials/record-failures.mjs::an_operation_left_unfinished_by_a_restart_is_settled
result-unpersistedrecording the final reply of credential operation {request}the record could not be written ({lower}), so the reply is only in the worker log{answer}free space and write access under the run results directory; the next status answers execution-interruptedinfra_down, exit 69, HTTP 502, retryabletests/credentials/record-failures.mjs::an_operation_whose_reply_cannot_be_recorded_is_logged
run-file-not-jsonreading what run {run} stated in {path}{path} is not JSON: the run writes it whole, so it was cut off or written by something else{path}: {bytes} bytes; parser: {answer}`weles runs show {run}` shows the run; submit the operation again under a new request idinfra_down, exit 69, HTTP 502, retryabletests/credentials/record-failures.mjs::a_run_statement_that_is_not_json_is_named
run-file-unreadreading what run {run} stated in {path}the system refused to read {path} ({errno}){path}: {errno}; system: {answer}give the account the worker runs as read access to {path}, then read the status againinfra_down, exit 69, HTTP 502, retryabletests/credentials/record-failures.mjs::a_run_statement_the_worker_cannot_read_is_named
enrol-fieldreading the enrolment request {request}an enrolment {mode} names {field} as {expects}, and the request does not{field}: {found}run it as skarbiec credential enrol role:<role> --provider google --order <order>, which writes every field this route readsrefused, exit 2, HTTP 400tests/credentials/enrolment-failures.mjs::an_enrolment_missing_a_field_is_refused_naming_it
enrol-providerenrolling an authenticator for {credential} at {provider}Weles enrols an authenticator at {providers} only, and the request names {provider}provider {provider}keep the seed of an account elsewhere with skarbiec totp set from the setup key the site showsrefused, exit 1, HTTP 409tests/credentials/enrolment-failures.mjs::an_enrolment_at_another_provider_is_refused
enrol-unknown{doing} {request}this worker admitted no enrolment under request {request}, so there is no run to answer or readenrolment records under {root}: none for {request}start it with skarbiec credential enrol role:<role> --provider google --order <order> on the worker that will run it; `weles worker status` names the worker that answersnot_found, exit 1, HTTP 404tests/credentials/enrolment-failures.mjs::answering_an_enrolment_never_admitted_is_refused
enrol-not-waitinganswering {answer} to enrolment {request}the run is {phase} and waits for {waiting}, so the answer {answer} has nothing to answerrun {run}: phase {phase}, waiting for {waiting}read where it stands with skarbiec credential enrol role:<role> --status --wait, and answer once it waits for yourefused, exit 1, HTTP 409tests/credentials/enrolment-failures.mjs::an_answer_the_run_does_not_wait_for_is_refused
enrol-gate-unmadeopening the place enrolment {request} waits for the owner atthe system refused to listen at {path} ({errno}), so the run could never hear the owner say ready and nothing was started{path}: {errno}; system: {answer}give the account the worker runs as write access to {root}; `weles doctor` names the run results directoryconfig, exit 1, HTTP 503tests/credentials/enrolment-failures.mjs::an_enrolment_whose_gate_cannot_open_is_refused
enrol-unansweredenrolment {request}the run ended while it waited for the owner to say {waiting}, so nothing was sent to the provider after that pointrun {run} ended waiting for {waiting}the order was spent; the vault owner issues a new one in Skarbiec Desktop and starts the enrolment again when the phone is in handrefused, exit 1, HTTP 409tests/credentials/enrolment-failures.mjs::a_run_that_ends_waiting_is_named
constraints-absentreading the credential storage constraints of this runcredential storage constraints are absent from this task: it was not started as a credential operationneither WELES_CREDENTIAL_CONSTRAINTS nor GENERIC_TASK_CONSTRAINTS is set for the runstart the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::a_run_without_constraints_stores_nothing
constraints-repeatedreading the credential storage constraints of this runmultiple credential constraint sources are not allowed: WELES_CREDENTIAL_CONSTRAINTS and GENERIC_TASK_CONSTRAINTS are both set, so which acquisition the run serves is ambiguousboth WELES_CREDENTIAL_CONSTRAINTS and GENERIC_TASK_CONSTRAINTS are set; the values are not shownstart the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::a_run_with_two_constraint_sources_is_refused
constraints-not-jsonreading the credential storage constraints of this runcredential storage constraints are not JSON{bytes} bytes; parser: {answer}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::constraints_that_are_not_json_are_refused
constraints-not-objectreading the credential storage constraints of this runcredential storage constraints are not an objectthe constraints are {kind}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::constraints_that_are_no_object_are_refused
storage-unauthorizedreading the credential storage constraints of this runcredential storage is not authorized for this task: store_secret_target is {target}, and only skarbiec storesstore_secret_target {target}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::constraints_storing_elsewhere_are_refused
secret-unnamedreading the credential storage constraints of this runcredential storage target is not in the exact Weles acquisition allowlist: the constraints name no secretsecret {secret}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::constraints_naming_no_secret_are_refused
secret-uncontractedreading the credential storage constraints of this runcredential storage target is not in the exact Weles acquisition allowlist: no acquisition contract is declared for secret {secret}secret {secret}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::constraints_of_an_undeclared_secret_are_refused
target-otherreading the credential storage constraints of this runcredential storage target is not in the exact Weles acquisition allowlist: the constraints name another {what} than the contract of {secret}constrained {constrained}; contract {declared}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::constraints_of_another_item_or_field_are_refused
field-unclassedreading the credential storage constraints of this runcredential storage field {field} has no field class: it is one of {classes}contract field {field} of secret {secret}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::a_contract_field_of_no_class_is_refused
account-email-missingreading the credential storage constraints of this runpassword credential storage requires an exact account email, and the constraints carry {email}account_email {email} for secret {secret}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::a_password_without_its_account_is_refused
request-unnamedreading the credential storage constraints of this runcredential storage requires an exact request id and operation: {what}request_id {request}, operation {operation}; the operations are {operations}start the credential operation again through POST /api/v1/credential-operations, which writes the constraints the acquisition declares; a run started otherwise stores no credentialconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::constraints_without_their_request_are_refused
capture-target-emptystoring a credentialcredential target is empty: the step names no element, label or textbox the credential is shown intarget {target}name the element the page shows the credential in (a selector, a label or a textbox name) in the steprefused, exit 2, HTTP 403tests/credentials/capture-failures.mjs::a_capture_naming_no_target_is_refused
capture-field-class-otherstoring the credential the page shows in Skarbiec item {item} field {field}credential field class does not match the exact Weles acquisition allowlist: the step stores a {asked}, and the contract a {declared}step field class {asked}; contract field class {declared}store the credential with the field class the acquisition contract names ({declared})refused, exit 2, HTTP 403tests/credentials/capture-failures.mjs::a_capture_of_another_field_class_is_refused
capture-origin-invalidstoring the credential the page shows in Skarbiec item {item} field {field}credential capture origin is not one absolute https origin: {origin}capture origin {origin} ({from})open the provider page over https, or declare its signup origin in the acquisition, then start the operation againconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::a_capture_from_a_page_not_on_https_is_refused
capture-origin-unopenedstoring the credential the page shows in Skarbiec item {item} field {field}credential source origin mismatch: no open page is on {origin}, so nothing the run shows may be captured{count} open page(s): {origins}go to the provider page on {origin} before the capture stepconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::a_capture_with_no_page_on_its_origin_waits
capture-shape-unshownstoring the credential the page shows in Skarbiec item {item} field {field}credential element was not found or did not match the required secret shape: {frames} frame(s) on {origin} show no value of the shape secret {secret} takestarget {target}; {frames} frame(s) searched, {seen} candidate value(s) of another shape; no value is shownreach the provider page that shows the credential, and name its element as the step targetconfig, exit 1, HTTP 503tests/credentials/capture-failures.mjs::a_capture_whose_page_shows_no_credential_waits
capture-record-unwrittenrecording the capture of request {request} in {path}the system refused to write the capture record ({errno}); the credential is stored in Skarbiec, and the worker answers the run as stating no capture{path}: {errno}; system: {answer}give the run write access to its recordings directory, then read the operation status: Skarbiec already holds the stored valueinfra_down, exit 69, HTTP 503, retryabletests/credentials/capture-failures.mjs::a_capture_whose_record_cannot_be_written_is_named

declarations#

16 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
declaration-unreadablereading the {kind} declaration {path}the declaration cannot be read: it is absent from this release, or this user may not read it{answer}reinstall the Weles release (`weles doctor` names what the installed release lacks), or make {path} readableconfig, exit 1, HTTP 503tests/declarations/failures.mjs::an_absent_declaration_is_named
declaration-not-jsonreading the {kind} declaration {path}the declaration is not JSON{path} ({bytes} bytes): {answer}correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/failures.mjs::a_declaration_that_is_not_json_is_named
declaration-shapereading the {kind} declaration {path}the declaration is not one object of schema {schema} holding a non-empty {member} arrayfound {found}correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/failures.mjs::a_declaration_of_another_shape_is_named
entry-incompletechecking {kind} entry {index} of {path}the entry is not an object naming {fields} as non-empty textentry {index}: {found}give entry {index} every one of {fields}; correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/failures.mjs::an_entry_without_its_fields_is_named
name-invalidchecking {kind} {name} of {path}its name is not <platform>.<verb> in lower case, or not the platform and verb the entry statesentry {index} names {name} for platform {platform} and verb {verb}name the entry {expected}, or correct its platform and verb; correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/failures.mjs::an_entry_whose_name_is_not_its_platform_and_verb_is_named
name-repeatedchecking {kind} {name} of {path}two entries declare the same name, so which one a run means is unknown{name} is entries {first} and {second}keep one of entries {first} and {second}; correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/failures.mjs::a_name_declared_twice_is_named
trajectory-outsidechecking {kind} {name} of {path}it names a trajectory outside src/trajectories/, where every reviewed trajectory livestrajectory {trajectory}name a reviewed trajectory under src/trajectories/ without ..; correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/failures.mjs::an_entry_naming_a_trajectory_outside_the_reviewed_ones_is_named
trajectory-missingchecking {kind} {name} of {path}the reviewed trajectory it names is not in this release{trajectory} does not exist under {root}add the trajectory to the release, or name one that exists; correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/failures.mjs::an_entry_naming_a_missing_trajectory_is_named
observation-invalidchecking observation {name} of {path}what it reads, its origin or its dwell is not one an observation can run with: {why}reads {reads}, origin {origin}, dwell {dwell}make it read one of feed, notifications, search_results (an origin carrying the query placeholder) or profile (one carrying the handle placeholder), from an https origin whose placeholders are among query, handle and subreddit, for a whole number of scrolls; correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/failures.mjs::an_observation_that_cannot_run_is_named
document-invalidchecking document {name} of {path}its origin, its media type or its login role is not one a document run can fetch with: {why}origin {origin}, media type {media_type}, login role {login_role}give it an https origin, one of the media types {media_types} and a Skarbiec role (lowercase letters, digits and hyphens) as its login_role; correct the {kind} declaration {path} in the Weles checkout and release it againconfig, exit 1, HTTP 503tests/declarations/documents.mjs::a_document_that_cannot_be_fetched_is_named
name-unnamedadmitting a {action} runthe run names its {kind} by something other than text{kind}: {given}name a declared {kind} as <platform>.<verb>; the declaration {path} lists themrefused, exit 2, HTTP 403tests/declarations/failures.mjs::a_run_naming_its_entry_by_no_text_is_refused
name-undeclaredadmitting a {action} run of {kind} {name}no entry of the declaration has that name{count} declared, e.g. {examples}name one of the {kind}s {path} declares, or declare {name} there and release itrefused, exit 2, HTTP 403tests/declarations/failures.mjs::a_run_naming_an_undeclared_entry_is_refused
both-namedadmitting a {action} runit names a declared {kind} and {other}, two answers to what the run does{kind}: {name}; {other}: {given}leave out {other}, or leave out {kind}refused, exit 2, HTTP 403tests/declarations/failures.mjs::a_run_naming_an_entry_and_its_own_target_is_refused
placeholder-unfilledadmitting observation {name}its origin {origin} carries the placeholder {placeholder}, and the run states no text for it{placeholder}: {given}state {placeholder} with the {reads} the run readsrefused, exit 2, HTTP 403tests/declarations/failures.mjs::an_observation_without_its_placeholder_is_refused
saved-trajectory-absentadmitting generic_saved_task run of saved trajectory {id}the run was queued without the saved trajectory it replaysparams.trajectory is {found}queue the run through Weles Web, which carries the saved trajectory in params.trajectoryrefused, exit 2, HTTP 403tests/declarations/failures.mjs::a_saved_run_without_its_trajectory_is_refused
saved-trajectory-otheradmitting generic_saved_task run of saved trajectory {id}the saved trajectory the run carries is another one than it namesparams.trajectory.id is {carried}queue the run again through Weles Web, so it carries trajectory {id}refused, exit 2, HTTP 403tests/declarations/failures.mjs::a_saved_run_carrying_another_trajectory_is_refused

design#

61 causes
CauseWhat failedWhyObservedFixCode, exit, HTTPTest
export-file-unreadreading the design export request {request}the {label} {path} could not be read ({errno}): it is absent, a directory, or the user may not read it{problem}; nothing was asked of Git, the vault or Figmaplace the {label} at {path}, or correct the path the request namesconfig, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::an_inventory_that_cannot_be_read_is_named
export-file-not-jsonreading the design export request {request}the {label} {path} is not JSON{bytes} bytes; the parser said: {problem}write the {label} as one JSON objectconfig, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::a_request_that_is_not_json_is_named
export-field-emptyreading the design export request {request}design export request requires a non-empty {field}, and {file} gives {given}{field}: {given}write {request} as {"inventory", "checkout", "remote", "branch", "credential": {"consumer", "item", "field", "scopeFile", "workloadId", "signingKeyFile"}[, "output"]}, paths relative to the requestconfig, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::a_request_without_a_field_is_named
export-path-absentreading the design export request {request}the {field} the request names does not resolve to an existing path ({errno}){field}: {path}, resolved against {root}create {path}, or name an existing one relative to the request fileconfig, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::a_checkout_that_does_not_exist_is_named
export-remote-urlreading the design export request {request}design export remote must name a configured Git remote, not a URL: a URL would push where no checkout configuredremote {remote}name the remote as `git -C {checkout} remote` lists it (such as origin)config, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::a_remote_that_is_a_url_is_refused
export-output-outsidereading the design export request {request}design export output must be a directory inside the checkout, relative to it and outside .gitoutput {output}, normalized to {managed}name the managed directory relative to the checkout (such as figma or libraries/<name>/figma)config, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::an_output_outside_the_checkout_is_refused
export-input-inside-outputreading the design export request {request}design export {label} must be outside the managed output directory {managed}, which the export replaces whole{label} {path} lies in {output}move {path} out of {managed}, or name another outputconfig, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::an_input_inside_the_output_is_refused
export-files-emptyreading the design export request {request}the Figma inventory {path} lists no company file, so there is nothing to exportcompanyFiles: {found}list each Figma file as {"name", "url"} in companyFiles of {path}config, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::an_inventory_without_files_is_refused
export-file-url-unparsedreading the design export request {request}{where}.url is not a URL{where}.url: {url}give the file's address as Figma shows it (https://www.figma.com/<kind>/<key>/<title>)config, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::a_file_url_that_is_no_url_is_refused
export-file-url-foreignreading the design export request {request}{where}.url must be an HTTPS Figma file URL (https://www.figma.com/<kind>/<key>/...): {why}{where}.url: {url}give the file's address as Figma shows it, without a user or passwordconfig, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::a_file_url_of_another_host_is_refused
export-file-repeatedreading the design export request {request}Figma inventory repeats file {key}, so its export would be written twice{first} and {where} both name file {key}keep one entry for file {key} in {path}config, exit 1, HTTP 503tests/design/exports/export-request-failures.mjs::an_inventory_repeating_a_file_is_refused
export-git-unstarted{step} in {checkout}git could not be started ({errno}): it is not installed or not on PATH, or {checkout} is not a directory git can enter`{command}`: {problem}; PATH {path}; {left}install git or put it on PATH (`command -v git` shows which one runs), then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::an_export_without_git_is_refused
export-git-killed{step} in {checkout}git was ended by {signal} before it answered: the host stopped it, it ran out of memory, or the export was interrupted`{command}` ended on {signal}; it said: {said}; {left}run the export againinfra_down, exit 69, HTTP 503, retryabletests/design/exports/export-checkout-failures.mjs::a_git_ended_by_a_signal_is_named
export-checkout-not-repositorychecking the checkout {checkout} a design export publishes intothe checkout is no git repository, so nothing can be committed or pushed from it`{command}` in {checkout} exited {status}: {said}; nothing was generated or changedname in the request the root of the clone the export publishes into (`git -C <dir> rev-parse --show-toplevel` shows a clone's root)config, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_checkout_that_is_no_repository_is_refused
export-checkout-unreadablechecking the checkout {checkout} a design export publishes intothe checkout holds {dotgit} and git still refused to read it as a repository: another user owns it (git's safe.directory), or its .git is damaged`{command}` in {checkout} exited {status}: {said}; nothing was generated or changed`git -C {checkout} status` shows what git refuses; `ls -ld {dotgit}` shows its owner; repair it, or name a clone this user ownsconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_repository_git_refuses_to_read_is_named
export-checkout-not-rootchecking the checkout {checkout} a design export publishes intothe checkout is a directory inside the repository rooted at {root}, not its root, so the managed directory would be read against another treegit rev-parse --show-toplevel answered {root}; nothing was generated or changedname {root} as the checkout in the request, and the managed directory relative to itconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_checkout_below_its_repository_root_is_refused
export-checkout-unbornchecking the checkout {checkout} a design export publishes intobranch {branch} of the checkout holds no commit yet, so there is nothing the export can publish on top of`{command}` in {checkout} exited {status}: {said}; nothing was generated or changedmake the first commit on {branch} and push it to the remote (`git -C {checkout} commit --allow-empty -m start`), then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_checkout_without_a_commit_is_refused
export-branch-invalidchecking the checkout {checkout} a design export publishes intothe request names branch {branch}, which is not a valid git branch name`{command}` in {checkout} exited {status}: {said}; nothing was generated or changedname the branch the export publishes to as git names it (`git check-ref-format --branch <name>`)refused, exit 2, HTTP 403tests/design/exports/export-checkout-failures.mjs::an_invalid_branch_name_is_refused
export-head-detachedchecking the checkout {checkout} a design export publishes intothe checkout is on no branch (a detached HEAD), so nothing it commits can be pushed to {branch}`{command}` in {checkout} exited {status}: {said}; HEAD is at {revision}; nothing was generated or changed`git -C {checkout} switch {branch}`, then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_checkout_on_no_branch_is_refused
export-branch-otherchecking the checkout {checkout} a design export publishes intothe checkout is on branch {current}, and the request publishes to {branch}git symbolic-ref --short HEAD answered {current}; nothing was generated or changed`git -C {checkout} switch {branch}`, or name {current} as the branch in the requestconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_checkout_on_another_branch_is_refused
export-remote-unknownchecking the checkout {checkout} a design export publishes intothe checkout has no remote {remote}`{command}` in {checkout} exited {status}: {said}; its remotes: {remotes}; nothing was generated or changedname one of the remotes the request's checkout has, or `git -C {checkout} remote add {remote} <url>`config, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_remote_the_checkout_lacks_is_refused
export-remote-urlschecking the checkout {checkout} a design export publishes intothe remote {remote} has {count} push URLs, and an export pushes to exactly one and reads it backpush URLs: {urls}; nothing was generated or changedkeep one push URL on {remote} (`git -C {checkout} remote set-url --push {remote} <url>`)config, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_remote_with_two_push_urls_is_refused
export-identity-unsetchecking the checkout {checkout} a design export publishes intogit has no {who} identity in this checkout, so the export commit could not be made`{command}` in {checkout} exited {status}: {said}; nothing was generated or changed`git -C {checkout} config user.name <name>` and `git -C {checkout} config user.email <address>`, then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_checkout_without_a_committer_is_refused
export-checkout-dirty{when} the checkout {checkout}the checkout holds {count} uncommitted or untracked paths, which the export would not replace and could not tell from its owngit status --porcelain lists {count}: {paths}; {left}commit, stash or remove them (`git -C {checkout} status` lists them), then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_dirty_checkout_is_refused
export-ignored-inside{when} the checkout {checkout}the managed directory {output} holds {count} ignored files, which the export would delete with the directory it replacesgit ls-files --others --ignored lists {count}: {paths}; {left}move the ignored files out of {output}, or stop ignoring them and commit them elsewhereconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::ignored_files_in_the_managed_directory_are_refused
export-checkout-moved{when} the checkout {checkout}the checkout's {what} changed while the export ran (from {before} to {now}): another program works in it{what} {before} at the start, {now} now; {left}let the other program finish, then run the export againrefused, exit 1, HTTP 403tests/design/exports/export-checkout-failures.mjs::a_checkout_that_moved_during_the_export_is_refused
export-remote-unreachablereading branch {branch} of remote {remote} ({url})the remote could not be read: its host does not answer, refuses the credentials, or holds no repository there`{command}` in {checkout} exited {status}: {said}; nothing was generated or changed`git -C {checkout} ls-remote {remote}` shows what the remote answers; run the export again once it answersinfra_down, exit 69, HTTP 503, retryabletests/design/exports/export-checkout-failures.mjs::a_remote_that_does_not_answer_is_named
export-remote-branch-absentreading branch {branch} of remote {remote} ({url})the remote holds no branch {branch}, so the export cannot tell it publishes on top of what the remote holdsgit ls-remote --exit-code answered no refs/heads/{branch} (exit {status}); nothing was generated or changed`git -C {checkout} push {remote} HEAD:refs/heads/{branch}` creates it, then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_remote_without_the_branch_is_refused
export-remote-divergentreading branch {branch} of remote {remote} ({url})the remote branch is at {remoteRevision}, not the checkout's {revision}, so a push would rewrite or lose commitslocal {revision}, remote {remoteRevision}; nothing was generated or changed`git -C {checkout} pull --ff-only {remote} {branch}` (or push the local commits), then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::a_divergent_remote_branch_is_refused
export-git-read-refused{step} in {checkout}git refused a read of a checkout it had read a moment before: another program changed, moved or locked the repository meanwhile`{command}` in {checkout} exited {status}: {said}; {left}`git -C {checkout} status` shows what git says now; once it answers, run the export againconfig, exit 1, HTTP 503tests/design/exports/export-checkout-failures.mjs::an_index_broken_during_the_export_is_named
export-output-not-directoryreading the managed directory {output} of {checkout}the managed directory is a {kind}, not a directory, so it cannot be replaced by an export{path} is a {kind}; nothing was generated or changedmove {path} aside, or name another managed directory in the requestconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_managed_path_that_is_a_file_is_refused
export-inventory-unreadreading the managed directory {output} of {checkout}the directory exists and its inventory.json could not be read ({errno}), so it cannot be told an earlier export{path}: {problem}; nothing was generated or changedname a managed directory that holds an earlier export or none yet; a directory of other files is not replacedconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_managed_directory_without_an_inventory_is_refused
export-inventory-not-jsonreading the managed directory {output} of {checkout}its inventory.json is not JSON, so the directory cannot be told an earlier export{path}: {bytes} characters; the parser said: {problem}; nothing was generated or changed`git -C {checkout} log -- {path}` shows who wrote it; restore the export's inventory or move the directory asideconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_managed_inventory_that_is_not_json_is_refused
export-inventory-foreignreading the managed directory {output} of {checkout}design export refuses {output}, a directory without an export inventory: its inventory.json holds no files list and generatedAt{path} holds {members}; nothing was generated or changedname the directory an earlier export wrote, or move {output} asideconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_managed_directory_of_another_kind_is_refused
export-build-not-directorypreparing the working directory {build} of {checkout}.build is a {kind}, not a directory, and the export keeps its lock and working files there{build} is a {kind}; nothing was generated or changedmove {build} aside, then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_build_path_that_is_a_file_is_refused
export-build-not-ignoredpreparing the working directory {build} of {checkout}.build/ is not ignored by the checkout, so the export's working files would show as changes and could be committed`{command}` in {checkout} exited {status}: {said}; nothing was generated or changedadd `.build/` to {checkout}/.gitignore and commit it, then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_checkout_that_does_not_ignore_build_is_refused
export-lock-heldtaking the export lock {lock}another design export holds the lock of this checkout, or one that ended without releasing it left it{lock} exists since {since} ({age} seconds); nothing was generated or changedwait for the other export to finish; when none runs (`pgrep -fl "weles design export"` lists none), remove {lock} and run againrefused, exit 1, HTTP 403tests/design/exports/export-publish-failures.mjs::a_lock_another_export_holds_is_refused
export-directory-unmadecreating {what} {path}the system refused to create it ({errno}): {build} is not writable by this user, or its disk is full{problem}; nothing was generated or changed; {left}`ls -ld {build}` shows its owner and mode, `df -h {build}` its free space; correct it, then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_build_directory_this_user_cannot_write_is_refused
export-install-failedpublishing the design export into {output} of {checkout}the new tree could not be moved into place ({errno}) at the step {step}{problem}; {left}`ls -ld {path}` shows the directory the move needed; correct it, then run the export againconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::an_install_the_system_refuses_is_named
export-commit-refusedpublishing the design export into {output} of {checkout}git refused to {step} the new tree: a hook rejected it, or the index is locked by another git`{command}` in {checkout} exited {status}: {said}; {left}`git -C {checkout} status` shows what is staged; resolve what git said, then commit and push {output} by hand or run the export againconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_commit_a_hook_refuses_is_named
export-push-refusedpushing the export commit {commit} to {remote}/{branch} ({url})the remote refused the push: the branch moved on since it was read, it is protected, or the credentials may not write it`{command}` in {checkout} exited {status}: {said}; {left}`git -C {checkout} push {remote} HEAD:refs/heads/{branch}` once what git said is resolvedrefused, exit 1, HTTP 403tests/design/exports/export-publish-failures.mjs::a_push_the_remote_refuses_is_named
export-readback-differsreading back {remote}/{branch} ({url}) after the exportthe remote branch is at {observed} after the push, not the export's commit {commit}: another push landed meanwhile, or the push was not keptlocal {commit}, remote {observed}; {left}`git -C {checkout} fetch {remote}` and `git -C {checkout} log {remote}/{branch}` show what the remote holds; publication was not confirmedinfra_down, exit 69, HTTP 503, retryabletests/design/exports/export-publish-failures.mjs::a_remote_that_reads_back_another_commit_is_named
export-cleanup-failedremoving {what} {path} after the export {outcome}the system refused to remove it ({errno}): it was removed, moved or made unwritable by another program while the export ran{problem}; {left}`ls -ld {path}` shows what is there; remove it by hand (`rm -r {path}`) when no export runsconfig, exit 1, HTTP 503tests/design/exports/export-publish-failures.mjs::a_lock_removed_during_the_export_is_named
parse-document-unreadreading the Figma document {source}the document could not be read ({errno}): it does not exist, is a directory, or this user may not read it{problem}; nothing was written`ls -l {source}` shows what is there; name a document file `weles design export` wrote (document.json.gz of a file folder)config, exit 1, HTTP 503tests/design/parse-failures.mjs::a_document_that_does_not_exist_is_named
parse-document-not-gzipreading the Figma document {source}its name ends in .gz and its {bytes} bytes are not gzip data, so it cannot be unpackedzlib said: {problem}; nothing was writtenname the document without .gz when it is plain JSON, or the document.json.gz the export wroteconfig, exit 1, HTTP 503tests/design/parse-failures.mjs::a_gz_document_that_is_not_gzip_is_refused
parse-document-not-jsonreading the Figma document {source}its {bytes} bytes are not one JSON document, so no node of it can be readthe parser stopped: {problem}; nothing was writtenexport the file again (`weles design export --provider figma --request <export-request.json>`); a document cut short was downloaded while the connection droppedconfig, exit 1, HTTP 503tests/design/parse-failures.mjs::a_document_that_is_not_json_is_refused
parse-document-not-objectreading the Figma document {source}it holds {found}, where a Figma file is the JSON object GET /v1/files/<key> answers{bytes} bytes parsed; nothing was writtenname the document.json.gz a design export wrote, not another JSON fileconfig, exit 1, HTTP 503tests/design/parse-failures.mjs::a_document_that_is_no_object_is_refused
parse-output-unwrittenwriting the {what} {path} of the Figma document {source}the system refused the write ({errno}): its directory does not exist, is not writable by this user, or the disk is full{problem}; written before it: {written}`ls -ld {directory}` shows the directory's owner and mode, `df -h {directory}` its free space; correct it, then parse againconfig, exit 1, HTTP 503tests/design/parse-failures.mjs::an_output_in_a_missing_directory_is_named
figma-unreachableasking Figma for {what} ({host}{path})the request got no answer ({errno}): the network, DNS or Figma is down, or a proxy refused the connection{problem}; nothing was published; {left}`curl -sSI https://api.figma.com/v1/me` shows whether Figma answers from this host; run the export again once it doesinfra_down, exit 69, HTTP 503, retryabletests/design/figma-failures.mjs::a_figma_that_does_not_answer_is_named
figma-token-refusedasking Figma for {what} ({host}{path})Figma refused the token the export acquired: it expired, was revoked, or may not read this fileHTTP {status} from {host}{path}{retry}: {body}; nothing was published; {left}store a token that reads the team's files under the request's credential item and field (`stado credentials doctor` names the vault), then run the export againauth, exit 1, HTTP 401tests/design/figma-failures.mjs::a_token_figma_refuses_is_named
figma-file-absentasking Figma for {what} ({host}{path})Figma holds no {what} there: the file was deleted or moved, or the inventory names a wrong keyHTTP {status} from {host}{path}{retry}: {body}; nothing was published; {left}open the file in Figma and copy its URL into the inventory's companyFiles, then run the export againnot_found, exit 1, HTTP 404tests/design/figma-failures.mjs::a_file_figma_does_not_hold_is_named
figma-rate-limitedasking Figma for {what} ({host}{path})Figma refused the request because the token asked too often in its windowHTTP {status} from {host}{path}{retry}: {body}; nothing was published; {left}run the export again after the Retry-After Figma named (or a minute when it named none)rate_limit, exit 69, HTTP 429, retryabletests/design/figma-failures.mjs::a_rate_limited_request_is_named
figma-unavailableasking Figma for {what} ({host}{path})Figma answered with a server error: its service failed or is overloadedHTTP {status} from {host}{path}{retry}: {body}; nothing was published; {left}https://status.figma.com shows an outage; run the export again once Figma answersinfra_down, exit 69, HTTP 503, retryabletests/design/figma-failures.mjs::a_figma_server_error_is_named
figma-request-refusedasking Figma for {what} ({host}{path})Figma refused the request itself as one it will not serve: too many node ids or too long a URL for one renderHTTP {status} from {host}{path}{retry}: {body}; nothing was published; {left}split the file's top-level frames across pages in Figma, or report the file to Weles's maintainers with this refusalrefused, exit 1, HTTP 403tests/design/figma-failures.mjs::a_request_figma_will_not_serve_is_named
figma-status-otherasking Figma for {what} ({host}{path})Figma answered with a status no request of the export expects (neither success, nor a refusal of the token, the file, the rate or the request)HTTP {status} from {host}{path}{retry}: {body}; nothing was published; {left}`curl -sSI https://api.figma.com{path}` shows what Figma answers now; report the status to Weles's maintainersunknown, exit 1, HTTP 500tests/design/figma-failures.mjs::a_status_figma_was_not_expected_to_give_is_named
figma-answer-unreadasking Figma for {what} ({host}{path})the connection dropped while the body of Figma's HTTP {status} answer was read{problem}; nothing was published; {left}run the export again; a large document needs a connection that holds for its whole downloadinfra_down, exit 69, HTTP 503, retryabletests/design/figma-failures.mjs::an_answer_cut_short_is_named
figma-answer-not-jsonasking Figma for {what} ({host}{path})Figma answered HTTP {status} with {bytes} bytes that are not JSON, where its API answers JSONthe parser said: {problem}; content-type {type}; nothing was published; {left}run the export again; a proxy between this host and Figma may have answered in its place (`curl -sS https://api.figma.com/v1/me` shows who answers)unknown, exit 1, HTTP 500tests/design/figma-failures.mjs::an_answer_that_is_not_json_is_named
figma-answer-shapeasking Figma for {what} ({host}{path})Figma answered {what} without {field}, which its API documents for that answerthe answer holds {members}; nothing was published; {left}`curl -sS -H "X-Figma-Token: <token>" https://api.figma.com{path}` shows the answer; report it to Weles's maintainers if Figma changed itunknown, exit 1, HTTP 500tests/design/figma-failures.mjs::an_answer_without_its_list_is_named
figma-asset-url-invaliddownloading {what} from the address Figma gavethe address is no absolute URL ({problem}), so it cannot be fetchedthe address is {length} characters, starting {start}; nothing was published; {left}run the export again; report the file to Weles's maintainers if Figma keeps giving such an addressunknown, exit 1, HTTP 500tests/design/figma-failures.mjs::an_asset_address_that_is_no_url_is_refused
figma-media-type-otherasking Figma for {what} ({host}{path})Figma served it as {type}, and neither that media type nor its path names a kind of file the export writes ({types})the download from {host}{path} was not written; nothing was published; {left}report the file and this media type to Weles's maintainers, who add its extension to src/figma/transfer.mjsunknown, exit 1, HTTP 500tests/design/figma-failures.mjs::a_download_of_an_unknown_media_type_is_refused
figma-write-failedwriting {what} {path} into the export's working treethe system refused the write ({errno}): the working tree was removed, is not writable by this user, or the disk is full{problem}; nothing was published; {left}`ls -ld {directory}` shows its owner and mode, `df -h {directory}` its free space; correct it, then run the export againconfig, exit 1, HTTP 503tests/design/figma-failures.mjs::a_working_tree_that_cannot_be_written_is_named