# Endpoint-specific error types

Canonical page: https://docs.ovok.com/errors/machine-codes

Ovok uses the following endpoint-specific machine codes to choose a stable Problem Details `type`. This inventory was checked against merged `ovok-core` development commit `6e295b659132da0d97f474508bbbea4b038310b3`, plus the four carer types added at `6a0d0f675`. It covers 82 app-defined types in addition to the status-derived types on the [Error responses](/errors) page. A source change that adds a new machine code must update this registry and its troubleshooting page.

Use the `type` URI as the stable category. Legacy response fields can vary by endpoint; do not assume the machine code is a top-level Problem Details `code`. The page for each type explains its status, likely cause, checks, and safe next step.

| Problem type | HTTP | Machine-code slug | Meaning |
| --- | ---: | --- | --- |
| [`account-exists`](/errors/account-exists) | 409 | `ACCOUNT_EXISTS` | An email address already belongs to an Ovok account, so registration or provisioning cannot create another account with it. |
| [`address-has-account`](/errors/address-has-account) | 409 | `ADDRESS_HAS_ACCOUNT` | A new carer's address already has an account, so accepting the invite cannot create a carer account for it. |
| [`already-subscribed`](/errors/already-subscribed) | 409 | `ALREADY_SUBSCRIBED` | The customer already has a subscription, so self-service checkout cannot create another one. |
| [`app-url-not-allowed`](/errors/app-url-not-allowed) | 400 | `APP_URL_NOT_ALLOWED` | The supplied patient or practitioner application URL points to the Ovok API host and cannot be used as a return destination. |
| [`app-url-not-configured`](/errors/app-url-not-configured) | 409 | `APP_URL_NOT_CONFIGURED` | The project has no usable patient or practitioner app URL for an invitation or wearable-connection flow that needs a return destination. |
| [`billing-disabled`](/errors/billing-disabled) | 403 | `BILLING_DISABLED` | Payments are not enabled in this Ovok deployment. |
| [`billing-hub`](/errors/billing-hub) | 403 | `BILLING_HUB` | This deployment is the central billing hub and does not accept this customer-facing billing operation. |
| [`client-id-reserved`](/errors/client-id-reserved) | 422 | `CLIENT_ID_RESERVED` | The Withings client ID belongs to Ovok's legacy Withings device integration. |
| [`cms-api-key-limit`](/errors/cms-api-key-limit) | 409 | `CMS_API_KEY_LIMIT` | The project already holds the maximum of 20 CMS API keys. |
| [`cms-api-key-not-found`](/errors/cms-api-key-not-found) | 404 | `CMS_API_KEY_NOT_FOUND` | The CMS API key identifier does not exist in the authenticated project. |
| [`connection-changed`](/errors/connection-changed) | 409 | `CONNECTION_CHANGED` | The patient reconnected the wearable provider during a sync, so nothing was written over the new connection. |
| [`connection-not-found`](/errors/connection-not-found) | 404 | `CONNECTION_NOT_FOUND` | The patient has no current wearable connection for the requested provider. |
| [`email-not-verified`](/errors/email-not-verified) | 403 | `EMAIL_NOT_VERIFIED` | The account's email address has not been verified, so this sign-in step is blocked. |
| [`encryption-unavailable`](/errors/encryption-unavailable) | 503 | `ENCRYPTION_UNAVAILABLE` | This server cannot encrypt a secret, so provider configuration was not saved. |
| [`enterprise-contract`](/errors/enterprise-contract) | 409 | `ENTERPRISE_CONTRACT` | The customer is billed under an Enterprise contract, so self-service subscription operations are unavailable. |
| [`events-unavailable`](/errors/events-unavailable) | 503 | `EVENTS_UNAVAILABLE` | Ovok could not read the project's request-event service in time or the service is temporarily unavailable. |
| [`feature-not-configured`](/errors/feature-not-configured) | 501 | `FEATURE_NOT_CONFIGURED` | The requested feature or integration is recognized but not configured or enabled in this deployment. |
| [`from-required`](/errors/from-required) | 422 | `FROM_REQUIRED` | The configured email provider requires a sender address that the project does not have. |
| [`invalid-link`](/errors/invalid-link) | 400 | `INVALID_LINK` | The verification link is invalid, expired, or already used. |
| [`invalid-secret`](/errors/invalid-secret) | 422 | `INVALID_SECRET` | The supplied provider secret does not match the format accepted by the selected integration. |
| [`invalid-setting-value`](/errors/invalid-setting-value) | 422 | `INVALID_SETTING_VALUE` | The supplied project setting is not valid for that setting's type or accepted values. |
| [`invalid-signature`](/errors/invalid-signature) | 401 | `INVALID_SIGNATURE` | A wearable provider notification arrived without a valid signature or URL token. |
| [`invalid-state`](/errors/invalid-state) | 422 | `INVALID_STATE` | The wearable authorization state is expired, already used, or bound to another provider or attempt. |
| [`invalid-switch`](/errors/invalid-switch) | 400 | `INVALID_SWITCH` | The project-switch token is malformed, expired, used at the wrong step, or already completed. |
| [`invalid-template-content`](/errors/invalid-template-content) | 422 | `INVALID_TEMPLATE_CONTENT` | Template content does not satisfy the selected email provider's requirements. |
| [`invalid-template-id`](/errors/invalid-template-id) | 422 | `INVALID_TEMPLATE_ID` | The template identifier is invalid for the selected email provider. |
| [`invitation-not-configured`](/errors/invitation-not-configured) | 409 | `INVITATION_NOT_CONFIGURED` | The project lacks a valid default access policy required for the invitation flow. |
| [`live-reads-over-capacity`](/errors/live-reads-over-capacity) | 503 | `LIVE_READS_OVER_CAPACITY` | The server reached its concurrent live-read limit and shed the request. |
| [`malformed-notification`](/errors/malformed-notification) | 400 | `MALFORMED_NOTIFICATION` | A wearable provider notification had a body that is neither a JSON object nor form fields. |
| [`monthly-request-cap`](/errors/monthly-request-cap) | 429 | `MONTHLY_REQUEST_CAP` | The project has used its monthly API request allowance. |
| [`no-subscription`](/errors/no-subscription) | 409 | `NO_SUBSCRIPTION` | There is no subscription on this billing customer to cancel. |
| [`not-parent-project`](/errors/not-parent-project) | 403 | `NOT_PARENT_PROJECT` | This billing operation must be made from the parent project that owns the sub-project's billing. |
| [`not-your-email`](/errors/not-your-email) | 403 | `NOT_YOUR_EMAIL` | The address in the project-switch request differs from the signed-in account. |
| [`not-your-switch`](/errors/not-your-switch) | 403 | `NOT_YOUR_SWITCH` | Another session started or owns this project-switch flow. |
| [`parent-project-has-no-access-policy`](/errors/parent-project-has-no-access-policy) | 424 | `PARENT_PROJECT_HAS_NO_ACCESS_POLICY` | The parent project lacks the default access policy required by this child-project operation. |
| [`password-required`](/errors/password-required) | 422 | `PASSWORD_REQUIRED` | The invite creates a new carer account, and the request did not include the password to sign in with. |
| [`patient-profile-required`](/errors/patient-profile-required) | 403 | `PATIENT_PROFILE_REQUIRED` | This wearable operation needs a patient session, but the current token does not identify a patient profile. |
| [`plan-limit-reached`](/errors/plan-limit-reached) | 403 | `PLAN_LIMIT_REACHED` | The project reached a resource or feature limit in its current plan. |
| [`practitioner-registration-not-configured`](/errors/practitioner-registration-not-configured) | 409 | `PRACTITIONER_REGISTRATION_NOT_CONFIGURED` | Practitioner registration is enabled but has no valid default access policy for new practitioners. |
| [`practitioner-without-access-policy`](/errors/practitioner-without-access-policy) | 409 | `PRACTITIONER_WITHOUT_ACCESS_POLICY` | A share could grant broader access than intended because the practitioner has no access policy. |
| [`project-context-required`](/errors/project-context-required) | 403 | `PROJECT_CONTEXT_REQUIRED` | The session has no project context for an operation scoped to one project. |
| [`project-not-empty`](/errors/project-not-empty) | 409 | `PROJECT_NOT_EMPTY` | The child project still contains patients, devices, locations, or child projects and cannot be deleted. |
| [`project-not-found`](/errors/project-not-found) | 404 | `PROJECT_NOT_FOUND` | The caller does not administer a project matching the requested tenant code, or a wearable webhook URL names a project that does not exist. |
| [`provider-configured`](/errors/provider-configured) | 409 | `PROVIDER_CONFIGURED` | The provider is already configured, so a create operation cannot add another configuration. |
| [`provider-mismatch`](/errors/provider-mismatch) | 409 | `PROVIDER_MISMATCH` | The template mapping provider does not match the provider configured for the project. |
| [`provider-not-available`](/errors/provider-not-available) | 404 | `PROVIDER_NOT_AVAILABLE` | The wearable provider is unavailable or disabled for this project. |
| [`provider-not-configured`](/errors/provider-not-configured) | 404 | `PROVIDER_NOT_CONFIGURED` | The requested email or wearable provider has not been set up for this project. |
| [`provider-rate-limited`](/errors/provider-rate-limited) | 503 | `PROVIDER_RATE_LIMITED` | The wearable provider is limiting requests from the project's app. |
| [`provider-unavailable`](/errors/provider-unavailable) | 502 | `PROVIDER_UNAVAILABLE` | The wearable provider failed, could not be reached, or answered something unreadable. |
| [`reconnect-required`](/errors/reconnect-required) | 409 | `RECONNECT_REQUIRED` | The wearable provider no longer accepts the connection; the patient has to connect it again. |
| [`related-person-without-access-policy`](/errors/related-person-without-access-policy) | 409 | `RELATED_PERSON_WITHOUT_ACCESS_POLICY` | A carer's membership has no access policy, so adding a share would narrow its access instead of extending it. |
| [`sharing-not-configured`](/errors/sharing-not-configured) | 409 | `SHARING_NOT_CONFIGURED` | The project has no patient-sharing access policy, so a carer share cannot be granted. |
| [`signals-audit-failed`](/errors/signals-audit-failed) | 503 | `SIGNALS_AUDIT_FAILED` | Ovok could not record an audit event, so the requested Signals change was not applied. |
| [`signals-bad-request`](/errors/signals-bad-request) | 422 | `SIGNALS_BAD_REQUEST` | Signals rejected the alert query, or the cursor was not issued by this list operation. |
| [`signals-code-invalid`](/errors/signals-code-invalid) | 422 | `SIGNALS_CODE_INVALID` | The vital-sign code is empty, malformed, too long, or contains unsupported characters. |
| [`signals-episodes-disabled`](/errors/signals-episodes-disabled) | 409 | `SIGNALS_EPISODES_DISABLED` | Episodic alerts are disabled for the project's Signals tenant. |
| [`signals-mint-failed`](/errors/signals-mint-failed) | 503 | `SIGNALS_MINT_FAILED` | Ovok could not provision the resident in Signals and rolled back the related resident creation. |
| [`signals-patient-not-enrolled`](/errors/signals-patient-not-enrolled) | 409 | `SIGNALS_PATIENT_NOT_ENROLLED` | The resident is not enrolled in the Signals tenant needed for this operation. |
| [`signals-project-migrating`](/errors/signals-project-migrating) | 409 | `SIGNALS_PROJECT_MIGRATING` | The project is moving to another Signals tenant, so tenant-dependent work is temporarily blocked. |
| [`signals-shared-tenant`](/errors/signals-shared-tenant) | 409 | `SIGNALS_SHARED_TENANT` | The project uses a shared Signals tenant, so this setting affects every project on that tenant. |
| [`signals-tenant-revoke-failed`](/errors/signals-tenant-revoke-failed) | 502 | `SIGNALS_TENANT_REVOKE_FAILED` | The child project was deleted but its Signals tenant could not be revoked. |
| [`signals-tenant-unavailable`](/errors/signals-tenant-unavailable) | 503 | `SIGNALS_TENANT_UNAVAILABLE` | The project's Signals tenant is unreachable or not ready to serve the request. |
| [`signals-threshold-not-editable`](/errors/signals-threshold-not-editable) | 409 | `SIGNALS_THRESHOLD_NOT_EDITABLE` | The threshold rule is not editable through this route, or a conflicting write is in progress. |
| [`signals-unavailable`](/errors/signals-unavailable) | 503 | `SIGNALS_UNAVAILABLE` | Ovok did not get a timely response from Signals for this operation. |
| [`signals-undo-failed`](/errors/signals-undo-failed) | 503 | `SIGNALS_UNDO_FAILED` | The Signals change could not be recorded or undone and requires operator reconciliation. |
| [`signup-closed`](/errors/signup-closed) | 403 | `SIGNUP_CLOSED` | Public sign-up is closed on this deployment. |
| [`state-store-unavailable`](/errors/state-store-unavailable) | 503 | `STATE_STORE_UNAVAILABLE` | Ovok's temporary wearable authorization-state store is unavailable. |
| [`subscription-key-not-used`](/errors/subscription-key-not-used) | 422 | `SUBSCRIPTION_KEY_NOT_USED` | A subscription key was sent to a wearable provider that does not accept one. |
| [`subscription-key-required`](/errors/subscription-key-required) | 422 | `SUBSCRIPTION_KEY_REQUIRED` | The wearable provider requires a subscription key that was not supplied. |
| [`sync-failed`](/errors/sync-failed) | 500 | `SYNC_FAILED` | A wearable sync failed on Ovok's side; nothing was written. |
| [`sync-in-progress`](/errors/sync-in-progress) | 409 | `SYNC_IN_PROGRESS` | A sync of this wearable connection is already running. |
| [`sync-not-supported`](/errors/sync-not-supported) | 501 | `SYNC_NOT_SUPPORTED` | Ovok can connect this wearable provider but does not sync its data yet. |
| [`sync-queue-unavailable`](/errors/sync-queue-unavailable) | 503 | `SYNC_QUEUE_UNAVAILABLE` | Ovok accepted a wearable provider notification but could not queue the sync it asks for. |
| [`sync-too-soon`](/errors/sync-too-soon) | 429 | `SYNC_TOO_SOON` | The wearable connection synced less than 15 minutes ago. |
| [`too-many-requests`](/errors/too-many-requests) | 429 | `TOO_MANY_REQUESTS` | The request rate exceeded an applicable Ovok limit. |
| [`trace-not-found`](/errors/trace-not-found) | 404 | `TRACE_NOT_FOUND` | No request event for this project has the supplied trace identifier. |
| [`transaction-too-large`](/errors/transaction-too-large) | 422 | `TRANSACTION_TOO_LARGE` | The FHIR transaction bundle exceeds Ovok's supported entry limit. |
| [`unknown-setting`](/errors/unknown-setting) | 400 | `UNKNOWN_SETTING` | The setting name is not supported by this project-settings route. |
| [`unknown-template`](/errors/unknown-template) | 400 | `UNKNOWN_TEMPLATE` | The template name is not in the supported template catalogue. |
| [`vat-id-required`](/errors/vat-id-required) | 422 | `VAT_ID_REQUIRED` | The customer's region requires a VAT ID for this billing operation. |
| [`webhook-not-supported`](/errors/webhook-not-supported) | 404 | `WEBHOOK_NOT_SUPPORTED` | Ovok takes no notifications from this wearable provider. |
| [`webhook-secret-not-used`](/errors/webhook-secret-not-used) | 422 | `WEBHOOK_SECRET_NOT_USED` | A `webhookSecret` was sent for a wearable provider that does not take one. |

FHIR routes return FHIR `OperationOutcome` resources; OAuth and MCP endpoints use their protocol error formats. These are not members of this Problem Details registry. See [FHIR OperationOutcome](/api/fhir/r4/operation-outcome), [refresh-token OAuth errors](/authentication/account/refresh-token), and the [MCP server troubleshooting guide](/working-with-ai-agents/mcp-server).
