langgenius/dify · warning · InvalidActionError

invalid_action

invalid_action

Error message

Document is being indexed, please try again later

What it means

Returned (HTTP 400, error_code `invalid_action`) by the segment enable/disable endpoint when a Redis flag `document_{document.id}_indexing` is still set. The flag is written while a document is being indexed/re-indexed and acts as a concurrency lock so segment status cannot be mutated mid-index. It is a transient, retryable rejection, not a data problem.

Source

Thrown at api/controllers/console/datasets/datasets_segments.py:395

                model_manager = ModelManager.for_tenant(tenant_id=current_tenant_id)
                model_manager.get_model_instance(
                    tenant_id=current_tenant_id,
                    provider=dataset.embedding_model_provider,
                    model_type=ModelType.TEXT_EMBEDDING,
                    model=dataset.embedding_model,
                )
            except LLMBadRequestError:
                raise ProviderNotInitializeError(
                    "No Embedding Model available. Please configure a valid provider in the Settings -> Model Provider."
                )
            except ProviderTokenNotInitError as ex:
                raise ProviderNotInitializeError(ex.description)
        segment_ids = request.args.getlist("segment_id")

        document_indexing_cache_key = f"document_{document.id}_indexing"
        cache_result = redis_client.get(document_indexing_cache_key)
        if cache_result is not None:
            raise InvalidActionError("Document is being indexed, please try again later")
        try:
            SegmentService.update_segments_status(segment_ids, action, dataset, document, session)
        except Exception as e:
            raise InvalidActionError(str(e))
        return SimpleResultResponse(result="success").model_dump(mode="json"), 200


@console_ns.route("/datasets/<uuid:dataset_id>/documents/<uuid:document_id>/segment")
class DatasetDocumentSegmentAddApi(Resource):
    @console_ns.doc(params=SegmentDocParams.DATASET_DOCUMENT)
    @setup_required
    @login_required
    @account_initialization_required
    @cloud_edition_billing_resource_check("vector_space")
    @cloud_edition_billing_knowledge_limit_check("add_segment")
    @cloud_edition_billing_rate_limit_check("knowledge")
    @console_ns.expect(console_ns.models[SegmentCreatePayload.__name__])
    @console_ns.response(200, "Segment created successfully", console_ns.models[SegmentDetailResponse.__name__])

View on GitHub (pinned to ef8544b173)

Solutions

  1. Wait for the document indexing job to finish, then retry the same enable/disable request.
  2. If indexing is genuinely done but the error persists, check whether a stale `document_{id}_indexing` key remains in Redis (e.g. `redis-cli GET document_<id>_indexing`) and delete it once you confirm no indexing task is running.
  3. Verify the Celery indexing worker is alive and the document's `indexing_status` is `completed` before retrying.

Example fix

// client: retry with backoff on invalid_action while document is indexing
async function toggleSegment(docId, segmentIds, action) {
  for (let i = 0; i < 5; i++) {
    const res = await fetch(`/console/api/datasets/${ds}/documents/${docId}/segments?action=${action}`,
      { method: 'PATCH', body: JSON.stringify({ segment_id: segmentIds }) });
    if (res.status !== 400) return res;
    const body = await res.json();
    if (body.code !== 'invalid_action' || !/indexing/i.test(body.message)) throw body;
    await new Promise(r => setTimeout(r, 1500 * (i + 1)));
  }
  throw new Error('Document still indexing after retries');
}
Defensive patterns

Strategy: retry

Validate before calling

# Pre-flight: confirm the document is not actively indexing before toggling segments.
import requests

def safe_update_status(base, headers, dataset_id, document_id, segment_ids, action):
    doc = requests.get(f"{base}/console/api/datasets/{dataset_id}/documents/{document_id}",
                       headers=headers).json()
    status = doc.get("data", {}).get("indexing_status")
    if status and status != "completed":
        raise RuntimeError(f"document indexing_status={status}; wait and retry")
    # optional: check the redis flag is unset via an admin endpoint if exposed
    return requests.patch(
        f"{base}/console/api/datasets/{dataset_id}/documents/{document_id}/segments",
        headers=headers,
        json={"segment_id": segment_ids, "action": action},
    )

Try / catch

# Treat invalid_action+indexing as transient and retry with backoff.
import time, requests

def update_status_with_retry(url, headers, payload, attempts=6, base_delay=1.5):
    for i in range(attempts):
        resp = requests.patch(url, headers=headers, json=payload)
        if resp.status_code == 400:
            body = resp.json()
            if body.get("code") == "invalid_action" and "indexing" in (body.get("message") or "").lower():
                time.sleep(base_delay * (i + 1))
                continue
        resp.raise_for_status()
        return resp
    raise RuntimeError("document still indexing after retries")

Prevention

When it happens

Trigger: Calling the segment status update endpoint (action=enable|disable) for a document whose indexing job has not finished clearing the `document_{id}_indexing` Redis key. Happens when a user toggles segment enable/disable immediately after uploading/re-indexing a document, or when a previous indexing run crashed and left the key orphaned.

Common situations: User re-indexes a document and clicks enable/disable on a segment before the indexing Celery task completes; a stalled/dead indexing worker leaves the Redis key behind so every subsequent toggle fails; Redis was flushed mid-index leaving inconsistent state.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/8e6a0638a3a7e436. Report an issue: GitHub.