{"record":{"id":"b0aa65c87fdab476","repo":"tinyhumansai/openhuman","slug":"runtime-unavailable-runtime-runtime-runtime","errorCode":null,"errorMessage":"Runtime unavailable: ${runtime.runtime} (${runtime.error ?? 'unavailable'})","messagePattern":"Runtime unavailable: (.+?) \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/components/skills/WorkflowRunnerBody.tsx","lineNumber":566,"sourceCode":"    try {\n      await skillsApi.cancelRun(runId);\n    } catch (err) {\n      log('cancelRun error: %s', err instanceof Error ? err.message : String(err));\n    }\n    setRecentRunsRefreshNonce(n => n + 1);\n  }, []);\n\n  const ensureRuntimeAvailability = useCallback(async () => {\n    const runtimeRequirement = inferRuntimeRequirement(selectedWorkflow);\n    if (!runtimeRequirement) return;\n\n    const resolved = await skillsApi.resolveRuntimes(runtimeRequirement);\n    const unavailable = resolved.runtimes.filter(runtime => !runtime.available);\n    if (unavailable.length === 0) return;\n\n    const prefix = t('settings.skillsRunner.error.runtimeUnavailable', 'Runtime unavailable');\n    const defaultReason = t('settings.skillsRunner.error.runtimeUnavailableDefault', 'unavailable');\n    throw new Error(\n      unavailable\n        .map(runtime => `${prefix}: ${runtime.runtime} (${runtime.error ?? defaultReason})`)\n        .join('; ')\n    );\n  }, [selectedWorkflow, t]);\n\n  const handleRun = useCallback(async () => {\n    if (!description) return;\n    // Re-entry guard: a second click before React applies the disabled state\n    // would otherwise fire `skill_runtime_run` twice and spawn two real runs.\n    if (runSubmitGuardRef.current) {\n      log('runWorkflow: ignoring re-entrant click while a run is starting');\n      return;\n    }\n    if (missingRequired.length > 0) {\n      setRun({\n        status: 'error',\n        message: `${t('settings.skillsRunner.error.missingRequired')} ${missingRequired.join(', ')}`,","sourceCodeStart":548,"sourceCodeEnd":584,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/components/skills/WorkflowRunnerBody.tsx#L548-L584","documentation":"Before running a workflow, the runner infers the managed runtimes it needs (inferRuntimeRequirement) and asks the core via skillsApi.resolveRuntimes; every runtime reporting available=false is joined into one error naming the runtime and its reason (runtime.error, defaulting to 'unavailable').","triggerScenarios":"Workflow uses node_exec/npm_exec or Python steps while the managed Node/Python runtime is not installed, disabled in config, or failed to download — resolveRuntimes marks it unavailable with the failure reason.","commonSituations":"Fresh install where the node_runtime harness-init step has not downloaded the toolchain yet; runtime disabled via config (node.enabled=false); a partial runtime download after an interrupted install.","solutions":["Install/enable the named runtime from Settings (skills runner / runtimes) and retry","Read the parenthesised reason: 'disabled' means flip the config flag; a download error means retry the runtime install","Re-run the workflow only after resolveRuntimes reports the requirement available"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Resolve runtimes when the workflow is selected, not at run time:\nconst req = inferRuntimeRequirement(selectedWorkflow);\nif (req) {\n  const resolved = await skillsApi.resolveRuntimes(req);\n  const missing = resolved.runtimes.filter(r => !r.available);\n  if (missing.length) { /* disable Run and show install hint with r.error */ }","typeGuard":"type ResolvedRuntime = { runtime: string; available: boolean; error?: string };\nconst missingRuntimes = (rs: ResolvedRuntime[]): ResolvedRuntime[] =>\n  rs.filter(r => !r.available);","tryCatchPattern":"try {\n  await ensureRuntimeAvailability();\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Runtime unavailable')) {\n    // parse the 'name (reason)' pairs and link each to its Settings install flow\n    return;\n  }\n  throw e;\n}","preventionTips":["Install managed runtimes (Settings → runtimes) before authoring node/python workflows","Surface runtime availability at workflow-selection time, not only at run click","Read the parenthesised reason to distinguish 'disabled' from 'install failed'"],"tags":["skills","runtime","workflow","availability"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}