# Tracking-plan errors

> Distinguish project selection, authorization, configuration and temporary failures when managing tracking plans.

Canonical page: https://anectico.com/docs/reference/tracking-plan-errors/


[Tracking plans](/docs/investigate/tracking-plans) are scoped to the authenticated
organization and one project. Organization credentials must select `project_id`;
a project-scoped credential can omit it or repeat its own project. Every read
requires `tracking_plans:read`. Writes require their additional permissions and
confirmation workflow.

## Project selection versus configuration

The following REST responses distinguish failures reported by the tracking-plan
service. A project selection problem is not a request to configure storage.

| HTTP status | Error | Message | Meaning and next step |
| --- | --- | --- | --- |
| 404 | `NotFound` | `project_id not found in this organization` | Select a project available in the authenticated organization. The response deliberately does not distinguish an absent UUID from a project owned by a different organization. |
| 400 | `FailedPrecondition` | `project_id must identify an active project` | The selected project belongs to this organization but is inactive. Use an active project or ask an administrator to review its state. |
| 400 | `FailedPrecondition` | `tracking data for project_id has been deleted` | The tracking operation reached a deleted data scope. Do not treat it as an empty plan list or assume retrying will recreate the data. |
| 400 | `FailedPrecondition` | `tracking operations are not configured` | The owning tracking service lacks a required configuration dependency. This is an operator/support problem, not evidence that the selected project belongs elsewhere. |
| 404 | `NotFound` | `tracking plan is not available` | The project check succeeded, but the requested plan or revision is unavailable, including retired plans. Check the plan identifier and revision separately from the project. |

These messages contain no other organization's identifier, project name or
activity state. An existing foreign project returns the same project-selection
response whether that project is active or inactive.

For example, an authorized organization-scoped request to
`GET /api/v1/analytics/tracking-plans?project_id=<missing-project-uuid>` returns
HTTP 404 with this body, not an empty success response or a server fault:

```json
{"error":"NotFound","message":"project_id not found in this organization"}
```

An active project in your organization with no tracking plans still returns
HTTP 200 with `plans: []` and `has_more: false`. A project-selection refusal on
this read does not require a mutation key.

Authentication and credential checks happen before the project lookup. A
conflicting project pin or missing tracking permission remains a 403 refusal;
it is not converted to a 404. A malformed UUID remains an invalid request.

## Service failures

An inconsistent project lookup response is a service fault, not an inactive or
foreign-project refusal. REST returns HTTP 500 with the fixed `internal_error`
code and `internal server error` message, without exposing dependency details.
A downstream temporary-unavailability response remains HTTP 503 with error
`unavailable`, message `the service could not answer this request; retry`, and
`Retry-After: 1`. Respect the retry delay rather than immediately repeating it.

A project lookup that exceeds its deadline remains a timeout: HTTP 504, not
HTTP 404 or HTTP 500. Its REST body uses the same fixed `internal_error` and
`internal server error` text as other sanitized server-fault responses; use the
HTTP status to distinguish the timeout. A timeout during a write is an uncertain
outcome, so follow the same-key recovery guidance below.

The status table describes REST, not the outer HTTP status of an MCP call. MCP
and CLI callers should inspect their own action/error result and follow the
same project-selection and uncertain-write guidance.
An unavailable project remains an MCP action error. The `not_found` tracking-plan
outcome applies only when the project lookup succeeded and the plan or revision
is unavailable.

## A refusal does not prove an earlier save was rolled back

Project authority is checked before accessing tracking storage and checked again
before returning read data or a success receipt. If access changes during the
operation, the response is withheld. A write may already have committed before
that final refusal, just as it may have committed before a connection was lost.

Preserve the exact original request and mutation key after an uncertain write.
Restore access to the original project and repeat that same operation with
the same mutation key. Do not generate a fresh mutation key just because
the acknowledgement was refused: doing so can create another revision. A later
not-found response or current-plan comparison cannot establish whether the
earlier write committed. See [Recover an uncertain save](/docs/investigate/tracking-plans#recover-an-uncertain-save).
