{"record":{"id":"ea9909abb0bc312f","repo":"langflow-ai/langflow","slug":"an-ingestion-for-this-connector-target-is-already","errorCode":null,"errorMessage":"An ingestion for this connector target is already queued or running. Wait for it to finish before starting another.","messagePattern":"An ingestion for this connector target is already queued or running\\. Wait for it to finish before starting another\\.","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/knowledge_bases.py","lineNumber":1893,"sourceCode":"            kb_name=kb_name,\n            source_type=payload.source_type,\n            source_config=source_config,\n        )\n\n        job_service = get_job_service()\n        job_id = uuid.uuid4()\n        try:\n            await job_service.create_job(\n                job_id=job_id,\n                flow_id=job_id,\n                job_type=JobType.INGESTION,\n                asset_id=asset_id,\n                asset_type=\"knowledge_base\",\n                user_id=current_user.id,\n                dedupe_key=dedupe_key,\n            )\n        except DuplicateJobError as exc:\n            raise HTTPException(\n                status_code=HTTPStatus.CONFLICT,\n                detail=(\n                    \"An ingestion for this connector target is already \"\n                    \"queued or running. Wait for it to finish before \"\n                    \"starting another.\"\n                ),\n            ) from exc\n\n        task_service = get_task_service()\n        await task_service.fire_and_forget_task(\n            job_service.execute_with_status,\n            job_id=job_id,\n            run_coro_func=KBIngestionHelper.perform_ingestion,\n            kb_name=kb_name,\n            kb_path=kb_path,\n            files_data=None,\n            chunk_size=payload.chunk_size,\n            chunk_overlap=payload.chunk_overlap,","sourceCodeStart":1875,"sourceCodeEnd":1911,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/knowledge_bases.py#L1875-L1911","documentation":"A 409 Conflict from the connector-ingest endpoint's idempotency guard: JobService.create_job rejects the job because a prior QUEUED/IN_PROGRESS/COMPLETED ingestion job carries the same dedupe key, built from (user, kb, source_type, source_config). FAILED/CANCELLED jobs do not block retries. This prevents double-clicking 'Ingest' from spawning duplicate connector jobs.","triggerScenarios":"POST /api/v1/knowledge_bases/{kb_name}/ingest/connector twice with the identical user, KB, source_type and source_config while the first ingestion job is still queued/running or already completed. Re-submitting an unchanged connector target after success reproduces it deterministically.","commonSituations":"Double-clicking the Ingest button, client retries on timeout that actually succeeded, or scripts re-running the same ingestion without changing any config parameter.","solutions":["Check the status of the existing job (GET /api/v1/task/{job_id} or the KB's job list) and wait for it to finish instead of re-submitting.","If you genuinely need to re-ingest the same target, cancel the running job first or wait for FAILED/CANCELLED state, which clears the dedupe block.","Change the source_config meaningfully (e.g. different folder id/path) if you intend a distinct ingestion.","Fix client retry logic to be idempotent-aware: treat 409 as 'already scheduled', not as a failure to retry."],"exampleFix":"# before\nresp = await client.post(url, json=payload)  # blind retry on any error\n\n# after: treat 409 as already-scheduled\nresp = await client.post(url, json=payload)\nif resp.status_code == 409:\n    job = await get_existing_job(kb, payload)  # poll existing job\n    return job","handlingStrategy":"try-catch","validationCode":"async def no_active_ingest_for_target(client, kb: str, payload: dict) -> bool:\n    jobs = await list_kb_jobs(client, kb)\n    for job in jobs:\n        if job[\"status\"] in (\"queued\", \"in_progress\"):\n            return False\n    return True","typeGuard":null,"tryCatchPattern":"try:\n    resp = await client.post(connector_url, json=payload)\nexcept HTTPStatusError as e:\n    if e.response.status_code == 409:\n        job = await find_existing_job(kb, payload)  # poll it instead of retrying\n        return job\n    raise","preventionTips":["Treat HTTP 409 as 'already scheduled', never as a retryable failure.","Disable the Ingest button client-side while a job for the same target is queued/running.","To force a fresh ingestion of an unchanged target, cancel the active job first or alter the config meaningfully."],"tags":["knowledge-base","connector-ingest","idempotency","http-409"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}