janhq/jan · error · Error
Invalid modelId: ${modelId}. Only alphanumeric and / _ - . c
Error message
Invalid modelId: ${modelId}. Only alphanumeric and / _ - . characters are allowed. What it means
Thrown by import() when modelId fails isValidModelId(). The validator requires the id to match ^[a-zA-Z0-9/_\-\.]+$ and have no empty/`.`/`..` path segments. This blocks path traversal and unsafe characters before the id is used to build a filesystem path. It is the first check in import(), before any disk access.
Source
Thrown at extensions/mlx-extension/src/index.ts:577
}
const newModelConfigPath = await joinPath([newFolderPath, 'model.yml'])
await fs.mv(modelFolderPath, newFolderPath).then(() =>
invoke('write_yaml', {
data: {
...modelConfig,
model_path: modelConfig?.model_path?.replace(
`mlx/models/${modelId}`,
`mlx/models/${model.id}`
),
},
savePath: newModelConfigPath,
})
)
}
override async import(modelId: string, opts: ImportOptions): Promise<void> {
if (!isValidModelId(modelId))
throw new Error(
`Invalid modelId: ${modelId}. Only alphanumeric and / _ - . characters are allowed.`
)
const configPath = await joinPath([
await this.getProviderPath(),
'models',
modelId,
'model.yml',
])
if (await fs.existsSync(configPath))
throw new Error(`Model ${modelId} already exists`)
const sourcePath = opts.modelPath
if (sourcePath.startsWith('https://')) {
// Download from URL to mlx models folder
const janDataFolderPath = await getJanDataFolderPath()
const modelDir = await joinPath([View on GitHub (pinned to fad3f12a14)
Solutions
- Sanitize modelId to the allowed charset (alphanumeric, /, _, -, .) before calling import().
- Reject or strip path-traversal segments ('..') upstream in the UI.
- Map disallowed characters (spaces -> '-', colons -> '-') deterministically.
- Reuse isValidModelId() to validate before showing the import action to the user.
Example fix
// before
await engine.import(rawName, { modelPath: url })
// after
function safeId(raw: string): string {
return raw.replace(/[^a-zA-Z0-9/_\-.]/g, '-').replace(/\/\.\.\//g, '')
}
const modelId = safeId(rawName)
await engine.import(modelId, { modelPath: url }) Defensive patterns
Strategy: validation
Validate before calling
import { isValidModelId } from './mlx-extension' // exported helper
function sanitizeModelId(raw: string): string {
return raw.replace(/[^a-zA-Z0-9/_\-.]/g, '-').replace(/\.\./g, '')
}
const modelId = sanitizeModelId(rawName)
if (!isValidModelId(modelId)) throw new Error('Cannot sanitize model id')
await engine.import(modelId, opts) Type guard
import { isValidModelId } from './mlx-extension'
function isSafeModelId(id: string): id is string {
return isValidModelId(id)
} Prevention
- Sanitize untrusted model names to the allowed charset before import.
- Block '..' and empty path segments at the input layer.
- Use isValidModelId() to gate the import button in the UI.
When it happens
Trigger: Calling import() with a modelId containing spaces, colons, non-ASCII, or special shell characters; an id with '../' segments or a leading/trailing slash producing empty parts; an id built from untrusted user input without sanitization.
Common situations: Pasting a Hugging Face repo id with '@', spaces, or parentheses; constructing modelId from a filename with spaces; attempted path traversal via '..'; id derived from model metadata with disallowed punctuation.
Related errors
- Invalid modelId: ${modelId}. Only alphanumeric and / _ - . c
- Model already loaded!
- No active MLX session found for model: ${modelId}
- No active MLX session found for model: ${opts.model}
- Model ${modelId} does not exist
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/690d78c4d54f2041.
Report an issue: GitHub.