{"record":{"id":"b457e4fb0f3dda0b","repo":"langgenius/dify","slug":"export-response-missing-data-field","errorCode":null,"errorMessage":"export response missing data field","messagePattern":"export response missing data field","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/api/app-dsl.ts","lineNumber":50,"sourceCode":"    })\n  }\n\n  async exportDsl(appId: string, query?: ExportQuery): Promise<string> {\n    const resp = await this.orpc.apps.byAppId.dsl.get({\n      params: { app_id: appId },\n      query:\n        query !== undefined\n          ? {\n              include_secret: query.includeSecret,\n              workflow_id: query.workflowId,\n            }\n          : undefined,\n    })\n    // The response schema is an open object {\"data\": \"<yaml string>\"}; the\n    // contract generator marks it as loose because the backend annotation\n    // does not narrow the shape. Extract `data` directly.\n    const data = (resp as Record<string, unknown>).data\n    if (typeof data !== 'string') throw new Error('export response missing data field')\n    return data\n  }\n\n  async checkDependencies(appId: string): Promise<CheckDependenciesResult> {\n    return this.orpc.apps.byAppId.dependencies.check.get({\n      params: { app_id: appId },\n    })\n  }\n}\n","sourceCodeStart":32,"sourceCodeEnd":60,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/cli/src/api/app-dsl.ts#L32-L60","documentation":"Raised by ExternalKnowledgeHitTestingApi.post (POST /datasets/{dataset_id}/external-hit-testing) when DatasetService.get_dataset returns None for the given dataset_id. The lookup is by primary key only (no tenant scoping at this line), so the ID simply does not exist in the datasets table. RBAC and permission checks run only after this existence check, so a 404 here precedes any 403. Werkzeug NotFound maps to HTTP 404.","triggerScenarios":"POST /console/api/datasets/{dataset_id}/external-hit-testing with a dataset_id that was deleted, never existed, or was copied incorrectly (e.g. stale URL copied from another environment). Also triggered when testing external knowledge retrieval against a dataset whose ID has a valid UUID format but no matching row.","commonSituations":"Stale dataset_id cached in the frontend after the dataset was deleted; cross-environment paste of a URL containing a dataset_id from dev into staging; race where the dataset is deleted between page load and the hit-testing request.","solutions":["Verify the dataset_id exists: call GET /console/api/datasets/{dataset_id} and confirm a 200 before issuing the hit-testing POST.","If the dataset was deleted, create a new external knowledge dataset and update the calling code/UI to use the new ID.","Reload the knowledge list in the console UI to refresh cached IDs before retrying."],"exampleFix":"// before\nconst res = await fetch(`/console/api/datasets/${staleDatasetId}/external-hit-testing`, { method: 'POST', body: ... });\n// after\nconst exists = await fetch(`/console/api/datasets/${datasetId}`).then(r => r.ok);\nif (!exists) { throw new Error('Dataset missing — refresh the knowledge list'); }\nconst res = await fetch(`/console/api/datasets/${datasetId}/external-hit-testing`, { method: 'POST', body: ... });","handlingStrategy":"validation","validationCode":"async function datasetExists(client, datasetId: string): Promise<boolean> {\n  const r = await client.get(`/console/api/datasets/${datasetId}`);\n  return r.status === 200;\n}\n// call before POST /datasets/{id}/external-hit-testing\nif (!(await datasetExists(client, datasetId))) {\n  throw new Error(`Dataset ${datasetId} does not exist`);\n}","typeGuard":"function isValidDatasetId(id: string): boolean {\n  // UUID v4 format expected by the <uuid:dataset_id> route converter\n  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n}","tryCatchPattern":"try {\n  await client.post(`/datasets/${datasetId}/external-hit-testing`, payload);\n} catch (e) {\n  if (e.response?.status === 404) {\n    await refreshDatasetList();  // clear stale id\n    return;\n  }\n  throw e;\n}","preventionTips":["Always resolve dataset_id from a fresh GET /datasets listing rather than hardcoding.","Invalidate cached dataset_ids whenever the dataset list is reloaded or the user switches tenants.","Treat 404 from any dataset-scoped endpoint as 'reload the list' on the client."],"tags":["dataset","external-knowledge","hit-testing","not-found","rest-api","console"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}