Tracking-plan errors
Distinguish project selection, authorization, configuration and temporary failures when managing tracking plans.
On this page
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:
{"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.