{"record":{"id":"72f4db173b9e2582","repo":"PaddlePaddle/PaddleOCR","slug":"text-recognition-model-dir-requires-text-recogniti","errorCode":null,"errorMessage":"text_recognition_model_dir requires text_recognition_model_name.","messagePattern":"text_recognition_model_dir requires text_recognition_model_name\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"paddleocr-js/packages/core/src/pipelines/ocr/shared.ts","lineNumber":497,"sourceCode":"  const modelSelection: Record<string, string | null> = {};\n  const assets: Record<string, ModelAsset> = {};\n  let hasAnyOption = false;\n\n  for (const role of OCR_MODEL_ROLES) {\n    const modelName = readAliasedOption(options, role.nameAliases, role.nameLabel) as\n      | string\n      | undefined;\n    const asset = readAliasedOption(options, role.assetAliases, role.assetLabel) as\n      | ModelAsset\n      | undefined;\n\n    if (modelName !== undefined) {\n      modelSelection[role.selectionKey] = modelName;\n      hasAnyOption = true;\n    }\n    if (asset !== undefined) {\n      if (modelName === undefined) {\n        throw new Error(role.assetRequirementError);\n      }\n      assets[role.assetKey] = asset;\n      hasAnyOption = true;\n    }\n  }\n\n  if (!hasAnyOption) {\n    return null;\n  }\n\n  return {\n    modelSelection,\n    assets\n  };\n}\n\nfunction resolveBaseModelSelection(\n  options: Record<string, unknown>,","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/paddleocr-js/packages/core/src/pipelines/ocr/shared.ts#L479-L515","documentation":"Same guard as the detection variant, but for the recognition role: getExplicitModelSelection() found a recognition asset option (text_recognition_model_dir or aliases) without text_recognition_model_name, and throws role.assetRequirementError with this text. The name is needed for inference.yml cross-validation of the loaded package.","triggerScenarios":"Passing { textRecognitionModelDir: '/models/rec/' } (or its aliases) without textRecognitionModelName to PaddleOCR.create().","commonSituations":"Self-hosting only the recognition model and passing just its path; fixing the detection pair but forgetting the recognition name after copy-paste.","solutions":["Add textRecognitionModelName matching the model_name in that directory's inference.yml.","Or remove the dir option to fall back to the default hosted recognition model."],"exampleFix":"// before\nconst ocr = await PaddleOCR.create({ textRecognitionModelDir: '/models/rec/' });\n\n// after\nconst ocr = await PaddleOCR.create({\n  textRecognitionModelName: 'PP-OCRv5_mobile_rec',\n  textRecognitionModelDir: '/models/rec/'\n});","handlingStrategy":"validation","validationCode":"if (opts.textRecognitionModelDir !== undefined && (opts.textRecognitionModelName ?? opts.text_recognition_model_name) === undefined) {\n  throw new TypeError('textRecognitionModelDir requires textRecognitionModelName');\n}","typeGuard":"function isRecDirWithName(o: Record<string, unknown>): boolean {\n  const dir = o.textRecognitionModelDir ?? o.text_recognition_model_dir;\n  const name = o.textRecognitionModelName ?? o.text_recognition_model_name;\n  return dir === undefined || typeof name === 'string';\n}","tryCatchPattern":"try {\n  const ocr = await PaddleOCR.create(opts);\n} catch (e) {\n  if (e instanceof Error && e.message === 'text_recognition_model_dir requires text_recognition_model_name.') {\n    opts = { ...opts, textRecognitionModelName: 'PP-OCRv5_mobile_rec' };\n    return PaddleOCR.create(opts);\n  }\n  throw e;\n}","preventionTips":["Mirror the detection pair rule for recognition: name and dir travel together.","Write one shared validator for both roles instead of ad-hoc checks."],"tags":["model-selection","configuration","recognition"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}