{"record":{"id":"45423fb27faeb901","repo":"usebruno/bruno","slug":"api-spec-is-not-registered-in-this-workspace","errorCode":null,"errorMessage":"API spec is not registered in this workspace.","messagePattern":"API spec is not registered in this workspace\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/bruno-electron/src/ipc/mock-server/index.js","lineNumber":44,"sourceCode":"  } catch {\n    const yaml = require('js-yaml');\n    return yaml.load(content);\n  }\n};\n\nconst readWorkspaceSpec = (workspacePath, specPath) => {\n  if (!specPath) {\n    throw new Error('API spec path is required.');\n  }\n\n  validateWorkspacePath(workspacePath);\n\n  const resolvedPath = path.resolve(specPath);\n  const isRegisteredSpec = getWorkspaceApiSpecs(workspacePath)\n    .some((spec) => spec.path && path.resolve(spec.path) === resolvedPath);\n\n  if (!isRegisteredSpec) {\n    throw new Error('API spec is not registered in this workspace.');\n  }\n\n  if (!fs.existsSync(resolvedPath)) {\n    throw new Error('API spec file not found.');\n  }\n\n  return parseSpecContent(fs.readFileSync(resolvedPath, 'utf8'));\n};\n\nconst registerMockServerIpc = (mainWindow) => {\n  mockServer.setMainWindow(mainWindow);\n\n  ipcMain.handle('renderer:mock-server-suggest-port', async (_event, payload = {}) => {\n    try {\n      const startPort = Number(payload.startPort) || undefined;\n      const port = await mockServer.suggestPort(startPort, {\n        additionalUsedPorts: payload.additionalUsedPorts || []\n      });","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/usebruno/bruno/blob/9bdd81c7bdc57006e5f5ebffb79321a8d979f712/packages/bruno-electron/src/ipc/mock-server/index.js#L26-L62","documentation":"Even with a path, readWorkspaceSpec resolves it and confirms it matches one of the specs registered in the workspace config (`getWorkspaceApiSpecs`). This is an allowlist: only specs the workspace explicitly registered can be read by the mock server, preventing arbitrary file reads via the mock-server channel.","triggerScenarios":"Passing an absolute path to a spec that exists on disk but was never added to workspace.yml's `specs`; a relative-vs-absolute mismatch so `path.resolve` comparison fails; the spec was removed from config but the renderer still references it.","commonSituations":"Pointing the mock server at an OpenAPI file without registering it first; workspace.yml hand-edited and the spec entry dropped; path stored relative in one place and absolute in another.","solutions":["Register the spec in the workspace first (addApiSpecToWorkspace, or via the UI).","Make the path you pass resolve identically to the registered entry - both absolute or both relative-to-workspace.","Re-add the spec via the UI if it was removed."],"exampleFix":"// before\nreadWorkspaceSpec(workspacePath, '/abs/path/to/openapi.yaml'); // not in workspace.yml\n// after - register first, then reference by the same resolved path\nawait addApiSpecToWorkspace(workspacePath, { name: 'petstore', path: 'specs/petstore.yaml' });\nreadWorkspaceSpec(workspacePath, path.join(workspacePath, 'specs/petstore.yaml'));","handlingStrategy":"validation","validationCode":"const path = require('path');\nconst { getWorkspaceApiSpecs } = require('../../utils/workspace-config');\nconst isRegistered = (workspacePath, specPath) => {\n  const resolved = path.resolve(specPath);\n  return getWorkspaceApiSpecs(workspacePath).some(s => s.path && path.resolve(s.path) === resolved);\n};","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always register a spec via addApiSpecToWorkspace (or the UI) before referencing it.","Keep spec paths in workspace.yml; don't pass ad-hoc absolute paths.","Compare paths via path.resolve to avoid relative/absolute mismatches."],"tags":["mock-server","openapi","security","allowlist","validation"],"backgroundTag":null,"analyzedSha":"9bdd81c7bdc57006e5f5ebffb79321a8d979f712","analyzedAt":"2026-08-13T04:09:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}