{"record":{"id":"fe170f1202fa4f40","repo":"danielmiessler/Fabric","slug":"response-error","errorCode":null,"errorMessage":"response.error","messagePattern":"response\\.error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/lib/api/base.ts","lineNumber":63,"sourceCode":"\n    const reader = response.body?.getReader();\n    if (!reader) throw new Error('Response body is null');\n\n    const decoder = new TextDecoder();\n    while (true) {\n      const { done, value } = await reader.read();\n      yield decoder.decode(value);\n\n      if (done) break;\n    }\n  }\n};\n\nexport function createStorageAPI<T extends StorageEntity>(entityType: string) {\n  return {\n    async get(name: string): Promise<T> {\n      const response = await api.fetch<T>(`/${entityType}/${name}`);\n      if (response.error) throw new Error(response.error);\n      return response.data as T;\n    },\n\n    async getNames(): Promise<string[]> {\n      const response = await api.fetch<string[]>(`/${entityType}/names`);\n      if (response.error) throw new Error(response.error);\n      return response.data as [];\n    },\n\n    async delete(name: string): Promise<void> {\n      const response = await api.fetch(`/${entityType}/${name}`, { method: 'DELETE' });\n      if (response.error) throw new Error(response.error);\n    },\n\n    async exists(name: string): Promise<boolean> {\n      const response = await api.fetch<boolean>(`/${entityType}/exists/${name}`);\n      if (response.error) throw new Error(response.error);\n      return response.data as boolean;","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/lib/api/base.ts#L45-L81","documentation":"createStorageAPI().get() unwraps the API envelope: api.fetch returns { data, error } and get() throws when error is truthy. This is an application-level error relayed verbatim from the backend, not an HTTP failure — fetch already succeeded with 2xx.","triggerScenarios":"GET /<entityType>/<name> returning JSON with a non-null error field: entity not found, invalid name, or a server-side read failure serialized into the envelope.","commonSituations":"Requesting a pattern/session/note deleted by another tab or process; name containing characters the backend rejects; storage backend (disk/DB) unavailable so the handler answers with an error envelope instead of a status code.","solutions":["Confirm the entity actually exists via the exists() method before assuming corruption","Check the backend handler for /<entityType>/:name to see what conditions produce this error string","URL-encode names with encodeURIComponent if the name may contain slashes or special characters"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!(await storageApi.exists(name))) {\n  throw new Error(`Entity '${name}' does not exist; nothing to get`);\n}","typeGuard":"function isEnvelopeError(e: unknown): e is Error {\n  return e instanceof Error && e.message.length > 0 && !e.message.startsWith('HTTP');\n}","tryCatchPattern":"try {\n  return await storageApi.get(name);\n} catch (e) {\n  if (e instanceof Error && /not found/i.test(e.message)) return undefined; // typed miss\n  throw e;\n}","preventionTips":["Check exists() (guarded) before get() when a miss is expected","Keep entity lists fresh before acting on user selections","URL-encode all name path segments"],"tags":["api-client","error-envelope","storage"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}