janhq/jan · error
Jan data folder is unavailable
Error message
Jan data folder is unavailable
What it means
dataFolder resolves the Jan data directory via the service hub; if getJanDataFolder() returns a falsy value it throws. All skill store operations (list/read/write/delete/invoke) depend on this path, so they fail fast when the app data folder cannot be determined.
Solutions
- Ensure the app/backend services are fully initialized before using the skill store
- Call skill APIs only after the app is ready (await app readiness event)
- Check app logs for service hub initialization failures
- Verify the Jan data folder setting is present in app configuration
Example fix
// before
const skills = await listSkills({ kind: 'project', folder })
// after
const appService = getServiceHub().app()
if (!appService) throw new Error('App service not initialized')
const skills = await listSkills({ kind: 'project', folder }) Defensive patterns
Strategy: try-catch
Validate before calling
const folder = await getServiceHub().app().getJanDataFolder() const ready = typeof folder === 'string' && folder.length > 0
Type guard
function hasDataFolder(f: unknown): f is string { return typeof f === 'string' && f.length > 0 } Try / catch
try { const skills = await listSkills(scope) } catch (e) { if (String(e).includes('data folder is unavailable')) await waitForAppReady(); else throw e } Prevention
- Initialize skill operations only after app-ready events
- Assert data folder presence during startup
- Avoid calling skill APIs from background/preload scripts before hydration
When it happens
Trigger: Any of listSkills/readSkill/writeSkill/deleteSkill/invokeSkill called before the app service hub is ready or when getJanDataFolder() returns null/undefined/empty.
Common situations: Calling skill APIs too early during app startup, backend/app service not initialized, or corrupted app state where the data folder was never set.
Understand the failure class
Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.
Related errors
- Jan data folder is unavailable
- Failed to decompress archive
- Failed to determine embedding context size
- Failed to normalize backend layout
- Folder not found
AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17).
Data as JSON: /api/errors/442fb2d2eeff386a.
Report an issue: GitHub.
Appendix: source
Thrown at web-app/src/lib/skillStore.ts:45
* rather than the plugin's. They are not redundant: `agent_skill_write` also runs
* `ensure_project`, which scaffolds `agent.toml`. That format is
* owned by `core::agent::project`, and the plugin must not learn to write it --
* owning no config format is what let the toolset be extracted at all. Routing
* project writes through guest-js would silently drop the scaffold.
*/
export type SkillScope =
| { kind: 'store' }
| { kind: 'project'; folder: string }
export const storeScope: SkillScope = { kind: 'store' }
export const projectScope = (folder: string): SkillScope => ({
kind: 'project',
folder,
})
const dataFolder = async (): Promise<string> => {
const folder = await getServiceHub().app().getJanDataFolder()
if (!folder) throw new Error('Jan data folder is unavailable')
return folder
}
export async function listSkills(scope: SkillScope): Promise<SkillMeta[]> {
if (scope.kind === 'project') {
return await invoke<SkillMeta[]>('agent_skill_list', {
project: scope.folder,
})
}
return await skillList(await dataFolder())
}
/** Raw SKILL.md text, frontmatter included. */
export async function readSkill(
scope: SkillScope,
name: string
): Promise<string> {
if (scope.kind === 'project') {View on GitHub (pinned to 7205d770c1)