Common rules
- Normative
- Draft 1.0
- Updated
- View as Markdown
9.1 Versions and extensions
Each LMSP request MAY carry these headers:
LMSP-Version: 1.0
LMSP-Client: example-client/1.2.0
LMSP-Version is the protocol version the client targets. LMSP-Client identifies the client software for diagnostics, as name/version. A service MUST NOT change protocol behavior based on it.
Rules:
- The
v1in the path denotes the major version. - A request that names an unknown major version is answered with
426 Upgrade Requiredand the error codeunsupported_protocol_version. - New optional fields MUST NOT break 1.x compatibility.
- Services and clients MUST ignore fields they do not know.
- Private extensions go in an
extensionsobject and are named in reverse-domain notation:
{
"extensions": {
"com.example.cache": {
"enabled": true
}
}
}
9.2 Idempotency
Requests that create something, such as creating a response, creating a task or loading a model, accept an idempotency key:
Idempotency-Key: <client-generated-unique-value>
The service stores the key together with a digest of the request body and the result:
- The same key with the same body returns the original result.
- The same key with a different body is answered with
409 Conflictandidempotency_conflict.
A key is scoped to the client and the endpoint. It SHOULD be a unique value of at most 255 characters, such as a ULID or a UUID. A service SHOULD keep keys for at least 24 hours.
A service MAY ignore the key on streaming requests. A client that needs safe retries uses a task.
9.3 Errors
Every error on the LMSP interface uses application/problem+json (RFC 9457):
{
"type": "urn:lmsp:error:model-not-found",
"title": "Model not found",
"status": 404,
"code": "model_not_found",
"detail": "No local model with id 'qwen3:14b-q4_k_m'",
"request_id": "req_01J8M9S6Y4W8C3P5R1V7Z2A0DH",
"retryable": false
}
| Field | Required | Meaning |
|---|---|---|
type |
Yes | URI that identifies the kind of error. LMSP uses urn:lmsp:error: followed by the code with hyphens instead of underscores. |
title |
Yes | Short, human-readable summary. |
status |
Yes | The HTTP status code. |
code |
Yes | Machine-readable error code, from the list below. |
detail |
No | Human-readable explanation of this occurrence. It MUST NOT contain secrets, prompts or generated content. |
request_id |
No | Identifier of the request, for correlation with service logs. |
retryable |
Yes | Whether repeating the request later can succeed. |
Common error codes:
| Code | HTTP status | Retryable | Meaning |
|---|---|---|---|
invalid_request |
400 | No | The request is malformed or has invalid parameters. |
unauthorized |
401 | No | The token is missing, invalid, expired or revoked, or a pairing code is wrong. |
forbidden |
403 | No | The token lacks the required scope, or the Origin or Host check failed. |
model_not_found |
404 | No | No local model has this id. |
model_not_ready |
409 | Yes | The model is not loaded and is not loaded on demand. |
model_load_failed |
500 | Yes | Loading the model failed. |
context_length_exceeded |
400 | No | The input does not fit in the context window of the model. |
unsupported_capability |
400 or 501 | No | The model or the service does not support what the request needs. An unimplemented optional endpoint answers 501. |
unsupported_protocol_version |
426 | No | The service does not support the requested major version. |
response_not_found |
404 | No | No stored response has this id. |
task_not_found |
404 | No | No task has this id. |
task_not_cancelable |
409 | No | The task has already succeeded or failed. |
idempotency_conflict |
409 | No | The idempotency key was already used with a different request body. |
event_history_expired |
410 | No | The requested events are older than the retention period. |
rate_limited |
429 | Yes | Too many requests. |
resource_exhausted |
503 | Yes | The device is out of memory or another resource. |
backend_unavailable |
503 | Yes | The model runtime cannot be reached. |
server_restarted |
503 | Yes | The service restarted while the task was unfinished. |
internal_error |
500 | Varies | An unexpected failure inside the service. |
The retryable field is authoritative. The column above shows the usual value. A service MAY define further codes. A client MUST handle a code it does not know by its HTTP status and its retryable field.
9.4 Health check
GET /lmsp/v1/health
{
"status": "ready",
"service_id": "svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2",
"uptime_seconds": 86420,
"loaded_models": 1,
"active_tasks": 2,
"storage": "ok"
}
| Field | Meaning |
|---|---|
status |
starting, ready, degraded or stopping. |
service_id |
The service id from the service description. |
uptime_seconds |
Seconds since the service started. |
loaded_models |
Number of models in the ready state. |
active_tasks |
Number of tasks that are queued, loading, running or cancelling. |
storage |
ok or error. |
The status is 200 OK when status is ready or degraded, and 503 Service Unavailable otherwise.
The health endpoint returns only operational status. It MUST NOT return model paths, prompts, access tokens or other sensitive information.