feat: improve UX for Ollama 404 errors (missing model)

- src/ollama-client.ts: Detect HTTP 404 on /api/chat and throw a descriptive
  ApiError with the model name and the exact ollama pull command needed.

- src/error-handler.ts: For API_ERROR type, return the error message directly
  instead of prefixing with 'API error: ', so the user-friendly 404 message
  is shown cleanly in the Obsidian notice.

- tests/ollama-client.test.ts: Update 404 assertions to match the new
  descriptive error message.
This commit is contained in:
2026-05-19 21:13:08 +02:00
parent 1ed2e39c3d
commit 138890b9d2
4 changed files with 28 additions and 4 deletions
+13 -1
View File
@@ -8130,6 +8130,12 @@ var OllamaClient = class {
signal: controller.signal
});
if (!response.ok) {
if (response.status === 404) {
throw new ApiError(
`Model "${this.model}" not found. Run \`ollama pull ${this.model}\` first.`,
404
);
}
throw new ApiError(`Ollama API error: ${response.status}`, response.status);
}
if (!response.body) {
@@ -8233,6 +8239,12 @@ var OllamaClient = class {
signal: controller.signal
});
if (!response.ok) {
if (response.status === 404) {
throw new ApiError(
`Model "${this.model}" not found. Run \`ollama pull ${this.model}\` first.`,
404
);
}
throw new ApiError(`Ollama API error: ${response.status}`, response.status);
}
const data = await response.json();
@@ -8849,7 +8861,7 @@ var ErrorHandler = class {
case "network_error" /* NETWORK_ERROR */:
return "Connection error. Please check if Ollama is running.";
case "api_error" /* API_ERROR */:
return `API error: ${error.message}`;
return error.message;
case "validation_error" /* VALIDATION_ERROR */:
return this.getUserFriendlyValidationMessage(error);
case "streaming_error" /* STREAMING_ERROR */:
+1 -1
View File
@@ -47,7 +47,7 @@ export class ErrorHandler {
case ErrorType.NETWORK_ERROR:
return 'Connection error. Please check if Ollama is running.';
case ErrorType.API_ERROR:
return `API error: ${error.message}`;
return error.message;
case ErrorType.VALIDATION_ERROR:
return this.getUserFriendlyValidationMessage(error);
case ErrorType.STREAMING_ERROR:
+12
View File
@@ -146,6 +146,12 @@ export class OllamaClient {
});
if (!response.ok) {
if (response.status === 404) {
throw new ApiError(
`Model "${this.model}" not found. Run \`ollama pull ${this.model}\` first.`,
404
);
}
throw new ApiError(`Ollama API error: ${response.status}`, response.status);
}
@@ -270,6 +276,12 @@ export class OllamaClient {
});
if (!response.ok) {
if (response.status === 404) {
throw new ApiError(
`Model "${this.model}" not found. Run \`ollama pull ${this.model}\` first.`,
404
);
}
throw new ApiError(`Ollama API error: ${response.status}`, response.status);
}
+2 -2
View File
@@ -214,7 +214,7 @@ describe('OllamaClient', () => {
mockFetch.mockResolvedValue({ ok: false, status: 404 });
await expect(client.streamChatAsPromise(mockMessages, mockTools)).rejects.toThrow(
'Ollama API error: 404'
'Model "llama3" not found. Run \`ollama pull llama3\` first.'
);
});
@@ -418,7 +418,7 @@ describe('OllamaClient', () => {
/* consume */
}
})()
).rejects.toThrow('Ollama API error: 404');
).rejects.toThrow('Model "llama3" not found. Run \`ollama pull llama3\` first.');
});
});