{"record":{"id":"959afa5c70673175","repo":"mastra-ai/mastra","slug":"sandbox-this-id-onstart-hook-failed-error","errorCode":null,"errorMessage":"Sandbox '${this.id}' onStart hook failed: ${error instanceof Error ? error.message : error}","messagePattern":"Sandbox '(.+?)' onStart hook failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workspace/sandbox/mastra-sandbox.ts","lineNumber":458,"sourceCode":"      // start() always observe a sandbox whose hook finished.\n      this.status = 'running';\n    } catch (error) {\n      this.status = 'error';\n      throw error;\n    }\n\n    const outcome = result?.outcome;\n\n    // Hook failures are FATAL: a caller must never observe a running sandbox\n    // whose setup failed. Nothing latches, so the next start() retries it.\n    // The environment acquired above is NOT released first: providers that\n    // implement find() reconnect to it on retry, but a create-only provider\n    // provisions another one and leaves the first to its idle timeout.\n    try {\n      await this._onStart?.({ sandbox: this, outcome });\n    } catch (error) {\n      this.status = 'error';\n      throw new Error(`Sandbox '${this.id}' onStart hook failed: ${error instanceof Error ? error.message : error}`, {\n        cause: error,\n      });\n    }\n\n    // Process any pending mounts after successful start\n    // Mount failures are tracked individually in MountManager and\n    // shouldn't mark the sandbox itself as errored\n    try {\n      await this.mounts?.processPending();\n    } catch (error) {\n      // Mount failures are tracked in MountManager — log but don't affect sandbox status\n      this.logger.warn('Unexpected error processing pending mounts', { error });\n    }\n\n    return result;\n  }\n\n  // ---------------------------------------------------------------------------","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workspace/sandbox/mastra-sandbox.ts#L440-L476","documentation":"Thrown by _executeStart in MastraSandbox when a user-supplied `onStart` hook throws during sandbox startup. The sandbox status is set to 'error' and the original error is attached as `cause`. This guards startup: a broken hook must not leave a sandbox that claims to be running while its initialization logic failed.","triggerScenarios":"Calling sandbox.start() (directly or via ensureRunning) when the sandbox has an `onStart` option/callback that throws — e.g. invalid data in the hook, a failed network call inside the hook, or a typo like calling an undefined variable inside the hook body.","commonSituations":"Provisioning steps (uploading files, registering DNS, warm-up API calls) placed in onStart that fail transiently; referencing `this` incorrectly in an arrow/loose function; fetching env vars that are missing in the deployment environment.","solutions":["Inspect error.cause to see the real error thrown by your onStart hook and fix the hook's logic.","Make the hook idempotent and wrap its fallible external calls with retry logic so transient failures don't fail startup.","If the hook's work is optional, catch its internal errors inside the hook and log instead of throwing.","Verify any env vars/secrets the hook needs exist in the runtime environment before calling start()."],"exampleFix":"// before\nnew MastraSandbox({ onStart: async ({ sandbox }) => { await uploadAssets(sandbox.id); } });\n// after\nnew MastraSandbox({\n  onStart: async ({ sandbox }) => {\n    for (let i = 0; i < 3; i++) {\n      try { await uploadAssets(sandbox.id); return; }\n      catch (e) { if (i === 2) logger.warn('upload failed, continuing', e); }\n    }\n  },\n});","handlingStrategy":"try-catch","validationCode":"const hook = opts.onStart;\nif (typeof hook !== 'function') throw new TypeError('onStart must be a function');\n// pre-check external deps the hook uses\nif (!process.env.UPLOAD_URL) throw new Error('UPLOAD_URL required by onStart hook');","typeGuard":"function isHookError(e: unknown): e is Error & { cause: unknown } {\n  return e instanceof Error && /onStart hook failed/.test(e.message) && 'cause' in e;\n}","tryCatchPattern":"try {\n  await sandbox.start();\n} catch (e) {\n  if (e instanceof Error && /onStart hook failed/.test(e.message)) {\n    logger.error('onStart hook failed', { cause: e.cause });\n    // fix hook or retry with backoff\n  } else throw e;\n}","preventionTips":["Keep onStart hooks minimal and idempotent; move heavy provisioning elsewhere.","Add internal try/catch with retries around fallible external calls in the hook.","Validate env vars and config the hook depends on before calling start()."],"tags":["sandbox","lifecycle-hook","startup"],"backgroundTag":"lifecycle-hook-threw","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}