The Lance table maintenance API provides interfaces to submit, query, list, and delete asynchronous tasks such as data file compaction, scalar/vector index creation, index optimization, and historical version cleanup.
API overview
Lance table maintenance provides 8 public HTTP APIs: 5 asynchronous task submission interfaces and 3 task query, list, and delete interfaces.
Lance Operation | HTTP Method | Endpoint Pattern |
POST | /lance/oss/v1/table/{id}/compact | |
POST | /lance/oss/v1/table/{id}/create_scalar_index | |
POST | /lance/oss/v1/table/{id}/create_vector_index | |
POST | /lance/oss/v1/table/{id}/optimize_indices | |
POST | /lance/oss/v1/table/{id}/cleanup | |
GET | /lance/oss/v1/table/{id}/tasks/{task_id} | |
GET | /lance/oss/v1/table/{id}/tasks | |
DELETE | /lance/oss/v1/table/{id}/tasks/{task_id} |
Access endpoints and table identifiers
All interfaces must be accessed through the Table Bucket third-level domain. In the request, {tableBucketHost} uses the domain name of the target Table Bucket. The server obtains the Table Bucket identity from the Host, and the URI does not carry the Table Bucket ARN.
The API prefix is /lance/oss/v1, which differs from the /lance/v1 prefix used by the standard Lance table management interfaces.
Parameter | Location | Required | Description |
id | path | Yes | Table identifier, in the format "namespace$table_name", for example prod$documents for the documents table in the prod namespace. This is not the table UUID. |
delimiter | query | No | Delimiter used to split the namespace and table name in id, supported by all 8 interfaces. The default value is $. If omitted or set to an empty string, $ is used to split. |
task_id | path | Required for Get/Delete | The task ID returned when you submit a task. The server only checks that this field is non-empty and does not validate the UUID format. |
When processing id, the server first URL-decodes it and then splits it by the delimiter. It must produce exactly two non-empty segments: the namespace and the table name. Only single-level namespaces are supported (e.g. prod); multi-level namespaces (e.g. a.b) are not supported. The table name follows the validation rules of the Lance table management interface, and the allowed character set for the namespace depends on the Table Bucket type.
A custom delimiter cannot contain /, :, or -, and supports multiple characters. Example:
POST /lance/oss/v1/table/prod__documents/compact?delimiter=__ HTTP/1.1
Host: {tableBucketHost}
Date: GMT Date
Authorization: SignatureValue
Content-Type: application/jsonAll operations validate that the table exists, the caller has permission, and the table format is LANCE. Tasks are isolated by the real Table ARN. A table recreated with the same name after deletion cannot read the previous table's tasks by name.
Request and response headers
SignatureValue is a signature placeholder. In an actual request, the client should generate it based on the configured OSS/Table signing method.
Host: {tableBucketHost}
Date: GMT Date
Authorization: SignatureValue
Content-Type: application/jsonThe body uses JSON. For requests with a non-empty body, providing Content-MD5 is recommended; when provided, the server validates its consistency with the body.
Successful responses of all 8 interfaces set:
x-oss-table-id: {table_id}The table_id here is the real ID in the server-side table metadata, which differs from the namespace$table_name in the URI. The Content-Type of a successful JSON response is application/json. A successful Delete response has no body.
Permissions
API | RAM Action | Authorization scope |
5 Submit APIs | oss:PutTableMaintenanceConfiguration | Current table |
GetLanceTaskStatus, ListLanceTasks | oss:GetTableMaintenanceJobStatus | Current table |
DeleteLanceTask | oss:PutTableMaintenanceConfiguration | Current table |
The server uses the real Table ARN obtained from the table lookup, combined with RAM, Table Bucket Policy, and Table Policy to perform authentication. This group of interfaces reuses existing maintenance-related Actions.
Asynchronous submission, parameter persistence, and task quota
A successful Submit returns HTTP 200, which indicates that the task has been persisted with an initial status of submitted. It does not indicate that the maintenance operation has completed.
Each POST creates a new task ID. There is currently no client request deduplication or Idempotency-Key semantics. Repeated submissions may create multiple tasks.
The server fills in default values for recognized parameters and writes them to the task params. Unknown JSON fields are usually ignored and do not automatically become task parameters. For example, the removed Compact batch_size.
Only the request format and basic parameters are validated on submission. Whether a column or index exists and whether a parameter combination can actually be executed are checked only when the task runs. Therefore, a successfully submitted task may still enter the failed state.
Currently, up to 1000 tasks are retained per Table ARN + task_type by default, including submitted, running, completed, and failed. Terminal tasks (status is
completed or failed) do not automatically release quota; you must delete the record by using DeleteLanceTask to release it. When the quota is reached, 429 / TaskQuotaExceeded / 10002 is returned; the client should catch this and retry. The quota limit is best-effort: under high concurrency it may briefly exceed the upper bound, so the client must not rely on this limit for assertions.
Task status
status | Meaning | Can Delete | Occupies quota |
submitted | Submitted, waiting for execution | No | Yes |
running | Running | No | Yes |
completed | Successfully executed, terminal state | Yes | Yes, until deleted |
failed | Execution failed, terminal state | Yes | Yes, until deleted |
Status transitions: submitted → running → completed; submitted and running can transition directly to failed. Terminal states (completed, failed) are irreversible. Get/List transparently pass through unknown statuses that appear in storage for forward compatibility, and unknown statuses still count toward the quota; currently only completed and failed can be deleted as terminal states.
Task execution failure and query failure are two different cases: if GetLanceTaskStatus successfully reads a failed task, the HTTP response still returns 200, with status="failed" and a non-empty error in the response; only when the query request itself fails (for example, the task does not exist or the parameters are invalid) is the top-level error structure described below used.
Error response format
This group of interfaces uses the unified Lance JSON error format:
{
"error": "TaskNotFound",
"code": 10000,
"detail": "The specified Lance maintenance task does not exist.",
"instance": "{request_id}"
}The detail is sample text and is subject to the actual server response.
HTTP status code | error | Lance code | Trigger scenario |
400 | InvalidInput | 13 | Required parameter missing, invalid enum or range, malformed table identifier, non-Lance table, List using mode/status, etc. |
400 | MalformedJson | 13 | JSON parsing failed or a recognized field has an incorrect type. |
400 | InvalidContinuationToken | 13 | The marker is empty, invalid, or out of the scope of the current table/task type. |
403 | LanceThirdLevelDomainRequired | 0 | Not accessed through the Table Bucket third-level domain. This error is mapped to UNSUPPORTED based on the specific error. |
403 | AccessDenied | 15 | Missing required access permissions. |
403 | SignatureDoesNotMatch / InvalidAccessKeyId | 16 | Invalid signature or access identity, mapped to UNAUTHENTICATED based on the specific error. |
404 | NamespaceNotExists | 1 | The namespace does not exist. Some name validation failures are also mapped to this error. |
404 | TableNotExists | 4 | The table does not exist. Some table name validation failures are also mapped to this error. |
404 | TaskNotFound | 10000 | The task for Get/Delete does not exist, has been deleted, or does not belong to the current table. |
409 | TaskStateConflict | 10001 | Deleting a task that is not in a terminal state or is not recognized as terminal by the current implementation. |
409 | TableOperationConflict | 14 | After the table lookup during authentication, a table identity change is detected during actual processing. |
429 | TaskQuotaExceeded | 10002 | The number of retained tasks for the current table and task type has reached the configured quota. |
500 | InternalError | 18 | Task storage not configured, storage errors converted, corrupted records, invalid server-side Compact default values, etc. |
Generic OSS request validation errors may also be returned. The error number is mapped precisely based on the error first and should not be inferred solely from the HTTP status code.
Integration sequence example
Call a Submit API on prod$documents and record the task_id from the response.
Call GetLanceTaskStatus on the same Table Bucket and table, and read task_info.status.
When you need to view historical tasks, call ListLanceTasks with the full
task_type, and use thenext_markerreturned in the response as themarkerfor the next request to paginate untilnext_markeris empty.After reading and saving the required results for completed/failed tasks, call DeleteLanceTask to release the task record quota.