{"record":{"id":"30f665202f708b76","repo":"mlflow/mlflow","slug":"custom-path-is-required-when-type-custom","errorCode":null,"errorMessage":"custom_path is required when type='custom'.","messagePattern":"custom_path is required when type='custom'\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"mlflow/server/assistant/api.py","lineNumber":783,"sourceCode":"        project_path = Path(project_location)\n\n    # Skills installation has side effects, so it requires an explicit provider\n    # selection instead of using _resolve_provider()'s runtime default.\n    provider = _get_selected_provider()\n    if provider is None:\n        raise HTTPException(\n            status_code=412,\n            detail=\"No assistant provider is configured or available.\",\n        )\n\n    match request.type:\n        case \"global\":\n            destination = provider.resolve_skills_path(Path.home())\n        case \"project\":\n            destination = provider.resolve_skills_path(project_path)\n        case \"custom\":\n            if not request.custom_path:\n                raise HTTPException(\n                    status_code=400,\n                    detail=\"custom_path is required when type='custom'.\",\n                )\n            destination = Path(request.custom_path).expanduser()\n\n    # Check if skills already exist - skip re-installation\n    if destination.exists():\n        if current_skills := list_installed_skills(destination):\n            return SkillsInstallResponse(\n                installed_skills=current_skills, skills_directory=str(destination)\n            )\n\n    installed = install_skills(destination)\n\n    return SkillsInstallResponse(installed_skills=installed, skills_directory=str(destination))\n\n\n@assistant_router.get(\"/providers/{provider}/models\")","sourceCodeStart":765,"sourceCodeEnd":801,"githubUrl":"https://github.com/mlflow/mlflow/blob/6a27f2decc0b76eb1b54af31849784addb357dbc/mlflow/server/assistant/api.py#L765-L801","documentation":"When `request.type == \"custom\"`, `install_skills_endpoint` requires `custom_path` because it has no other way to determine the destination directory. A missing/empty `custom_path` raises HTTP 400 'custom_path is required when type=custom.' The path is later expanduser()'d, so '~' is accepted.","triggerScenarios":"POSTing {\"type\": \"custom\"} with `custom_path` absent, null, or empty string; a client that maps a UI 'custom location' toggle without carrying the path field into the payload.","commonSituations":"Hand-written curl/script payloads; UI form bugs where the custom-path textbox is hidden but type is still 'custom'; copying a global-install payload and only changing `type`.","solutions":["Include a non-empty `custom_path` in the request, e.g. {\"type\": \"custom\", \"custom_path\": \"/home/me/project/.claude/skills\"}.","Use '~' if you want the server user's home expanded (expanduser is applied server-side).","If you meant a global install, change `type` to \"global\" and drop `custom_path` entirely."],"exampleFix":"// before\n{\"type\": \"custom\"}\n\n// after\n{\"type\": \"custom\", \"custom_path\": \"~/repos/app/.claude/skills\"}","handlingStrategy":"validation","validationCode":"function validateSkillsInstall(req) {\n  if (req.type === 'custom' && !(typeof req.custom_path === 'string' && req.custom_path.trim())) {\n    throw new Error(\"custom_path is required when type='custom'\");\n  }\n}","typeGuard":"function hasCustomPath(r) { return r.type !== 'custom' || (typeof r.custom_path === 'string' && r.custom_path.trim().length > 0); }","tryCatchPattern":"const res = await fetch(`${base}/assistant/skills/install`, {method: 'POST', body: JSON.stringify(req)});\nif (res.status === 400) {\n  const { detail } = await res.json();\n  if (detail.includes('custom_path is required')) req = {...req, custom_path: await promptForPath()};\n}","preventionTips":["Make custom_path a required form field in the client whenever the 'custom' type is chosen.","Validate payloads against the endpoint's request schema in tests before shipping UI changes.","Use '~'-prefixed paths when you want server-side home expansion.","Default the custom path input to a sensible project location instead of leaving it blank."],"tags":["http-400","validation","request-schema","assistant"],"backgroundTag":"missing-required-parameter","analyzedSha":"6a27f2decc0b76eb1b54af31849784addb357dbc","analyzedAt":"2026-08-29T20:54:51.419Z","schemaVersion":2},"datasetVersion":"2026-08-29T22:17:34.462Z"}