{"record":{"id":"fc8a4f664d369368","repo":"TryGhost/Ghost","slug":"apikey-not-found","errorCode":null,"errorMessage":"ApiKey not found.","messagePattern":"ApiKey not found\\.","errorType":"exception","errorClass":"NotFoundError","httpStatus":404,"severity":"error","filePath":"ghost/core/core/server/services/integrations/integrations-service.js","lineNumber":19,"sourceCode":"const {NotFoundError, InternalServerError} = require('@tryghost/errors');\nconst tpl = require('@tryghost/tpl');\n\nconst messages = {\n    notFound: '{resource} not found.'\n};\n\nclass IntegrationsService {\n    constructor({IntegrationModel, ApiKeyModel}) {\n        this.IntegrationModel = IntegrationModel;\n        this.ApiKeyModel = ApiKeyModel;\n    }\n\n    async edit(data, options) {\n        if (options.keyid) {\n            const model = await this.ApiKeyModel.findOne({id: options.keyid});\n\n            if (!model) {\n                throw new NotFoundError({\n                    message: tpl(messages.notFound, {\n                        resource: 'ApiKey'\n                    })\n                });\n            }\n            try {\n                await this.ApiKeyModel.refreshSecret(model.toJSON(), Object.assign({}, options, {id: options.keyid}));\n\n                return await this.IntegrationModel.findOne({id: options.id}, {\n                    withRelated: ['api_keys', 'webhooks']\n                });\n            } catch (err) {\n                throw new InternalServerError({\n                    err: err\n                });\n            }\n        }\n","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/ghost/core/core/server/services/integrations/integrations-service.js#L1-L37","documentation":"A NotFoundError from `IntegrationsService.edit` when `options.keyid` is set and `ApiKeyModel.findOne({id: options.keyid})` returns no model. This path refreshes an integration's API-key secret; if the supplied key id does not exist the service refuses to proceed. It does not check the key's integration ownership beyond existence.","triggerScenarios":"PUT to edit an integration with a `keyid` parameter referring to an API key id that was deleted, never existed, or belongs to a different integration. The `require`-less `findOne` returns null and the service throws before attempting the secret refresh.","commonSituations":"The API key was rotated/deleted in a separate request before this call; the client cached a stale key id; the key id was copy-pasted incorrectly (truncated/wrong field); an integration was recreated and old key ids are invalid.","solutions":["Re-fetch the integration's current API keys (`GET /integrations/{id}/?include=api_keys`) and use a live `keyid`.","Confirm the `keyid` belongs to the integration being edited.","Remove the `keyid` param if you only want to edit integration metadata, not refresh a secret.","If the key truly no longer exists, create a new API key for the integration instead of refreshing a dead one."],"exampleFix":"// before\nawait integrations.edit({id}, {keyid: staleKeyId, ...}); // -> NotFoundError\n\n// after\nconst fresh = await integrations.findOne({id}, {withRelated: ['api_keys']});\nconst keyid = fresh.api_keys[0].id;\nawait integrations.edit({id}, {keyid});","handlingStrategy":"validation","validationCode":"async function assertApiKeyExists(apiKeyModel, keyid) {\n  const m = await apiKeyModel.findOne({id: keyid});\n  if (!m) throw new Error(`ApiKey ${keyid} not found; refresh the integration's keys`);\n  return m;\n}","typeGuard":"const apiKeyExists = async (model, id) => Boolean(await model.findOne({id}));","tryCatchPattern":"try {\n  await integrations.edit({id}, {keyid});\n} catch (err) {\n  if (err.type === 'NotFoundError' && /ApiKey not found/i.test(err.message)) refreshApiKeys();\n  else throw err;\n}","preventionTips":["Re-fetch the integration's api_keys before refreshing a secret.","Confirm keyid belongs to the integration being edited.","Omit keyid when only editing metadata."],"tags":["integrations","api-key","not-found","admin-api"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}