Ihr kennt das bestimmt: Die Astro-Anwendung läuft lokal perfekt, aber beim Build oder zur Laufzeit erscheint plötzlich die kryptische Meldung „Only finite numbers (not Infinity or NaN) can be passed as arguments“. Der Build bricht ab, die Datenbank verweigert den Eintrag, und ihr steht vor einem Fehler, der auf den ersten Blick wenig Sinn ergibt.
Bei Never Code Alone unterstützen wir seit über 15 Jahren Entwicklungsteams bei genau solchen Problemen. Unsere Spezialisierung auf Softwarequalität und Open Source bedeutet, dass wir täglich mit den Feinheiten moderner Frameworks wie Astro arbeiten. Dieser Artikel zeigt euch, wie ihr den Fehler versteht, debuggt und dauerhaft vermeidet.
1. Was bedeutet der Fehler „Only finite numbers“ in Astro JS?
Der Fehler signalisiert, dass irgendwo in eurem Code ein numerischer Wert übergeben wird, der entweder Infinity, -Infinity oder NaN (Not a Number) ist. JavaScript erlaubt diese Werte als Teil des Number-Types, aber viele Funktionen und APIs – insbesondere Datenbank-Operationen in Astro DB – akzeptieren sie nicht.
Die Meldung tritt typischerweise auf, wenn ihr Daten an Astro DB übergebt, JSON serialisiert oder mathematische Berechnungen durchführt, deren Ergebnis kein gültiger finiter Wert ist. Das Problem dabei: Der Fehler zeigt oft nicht direkt auf die problematische Stelle, sondern erst dort, wo der ungültige Wert verarbeitet wird.
// Diese Werte verursachen den Fehler
const problematisch = Infinity;
const auchProblematisch = NaN;
const nochMehr = 1 / 0; // ergibt Infinity
const undefined_calc = parseInt("nicht-eine-zahl"); // ergibt NaN
2. Warum akzeptiert Astro DB keine Infinity oder NaN Werte?
Astro DB basiert auf libSQL/Turso und muss Werte in einem Format speichern, das über verschiedene Systeme hinweg konsistent bleibt. Infinity und NaN sind JavaScript-spezifische Konzepte, die in SQL-Datenbanken keine direkte Entsprechung haben.
Wenn ihr einen NaN-Wert in eine Datenbank schreiben würdet, was sollte bei einer späteren Abfrage zurückkommen? Die Antwort ist nicht eindeutig, und genau deshalb blockiert Astro diese Werte proaktiv. Das ist eigentlich ein Feature – der Fehler verhindert, dass inkonsistente Daten in eure Datenbank gelangen.
In unserer Consulting-Praxis sehen wir häufig, dass Teams diesen Schutz zunächst als Hindernis empfinden. Tatsächlich hilft er aber, Datenqualitätsprobleme frühzeitig zu erkennen, bevor sie in der Produktion Schaden anrichten.
3. Wie debugge ich die Ursache für NaN-Werte in meinem Code?
Das Aufspüren von NaN-Werten kann frustrierend sein, weil sie sich oft durch mehrere Berechnungen propagieren, bevor der Fehler auftritt. Der effektivste Ansatz ist systematisches Logging an strategischen Stellen.
// Hilfsfunktion für Debug-Logging
function debugNumber(value, label) {
if (!Number.isFinite(value)) {
console.error(`[DEBUG] ${label}: Ungültiger Wert gefunden!`, {
value,
isNaN: Number.isNaN(value),
isInfinity: !Number.isFinite(value) && !Number.isNaN(value),
stack: new Error().stack
});
}
return value;
}
// Verwendung in eurem Code
const result = debugNumber(calculateSomething(), 'Berechnungsergebnis');
Nutzt die Browser-DevTools oder Node.js-Debugger, um Breakpoints an verdächtigen Stellen zu setzen. Achtet besonders auf Stellen, an denen externe Daten – etwa aus APIs oder Formularen – in Berechnungen einfließen.
4. Welche JavaScript-Operationen erzeugen Infinity und NaN?
Die häufigsten Quellen für diese problematischen Werte sind mathematische Edge-Cases und Typkonvertierungen. Hier ein Überblick der typischen Verursacher:
// Division durch Null ergibt Infinity
console.log(10 / 0); // Infinity
console.log(-10 / 0); // -Infinity
// Mathematisch undefinierte Operationen ergeben NaN
console.log(0 / 0); // NaN
console.log(Math.sqrt(-1)); // NaN
console.log(Math.log(-1)); // NaN
// Fehlgeschlagene Parsing-Operationen
console.log(parseInt("abc")); // NaN
console.log(parseFloat(""); // NaN
console.log(Number(undefined)); // NaN
// Operationen mit NaN propagieren NaN
const x = NaN;
console.log(x + 5); // NaN
console.log(x * 10); // NaN
Das Tückische an NaN ist seine Ansteckungswirkung: Sobald ein NaN in einer Berechnung auftaucht, wird auch das Ergebnis zu NaN. Deshalb ist es wichtig, ungültige Werte so früh wie möglich abzufangen.
5. Wie prüfe ich korrekt auf NaN und Infinity in JavaScript?
Die Prüfung auf diese Werte hat ihre Eigenheiten. Der Klassiker value === NaN funktioniert nicht, weil NaN der einzige JavaScript-Wert ist, der nicht sich selbst gleicht.
// Falsche Prüfung
const wert = NaN;
console.log(wert === NaN); // false - funktioniert nicht!
// Korrekte Prüfungen
console.log(Number.isNaN(wert)); // true
console.log(Number.isFinite(wert)); // false
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite(42)); // true
// Umfassende Validierungsfunktion
function isValidNumber(value) {
return typeof value === 'number' && Number.isFinite(value);
}
Verwendet Number.isFinite() als eure Standard-Validierung für numerische Werte. Diese Funktion gibt nur true zurück, wenn der Wert eine echte, endliche Zahl ist – also weder NaN, noch Infinity, noch ein nicht-numerischer Typ.
6. Wie verarbeite ich externe API-Daten sicher in Astro?
Externe Datenquellen sind eine der häufigsten Ursachen für NaN-Probleme. JSON kennt weder NaN noch Infinity, aber fehlende oder ungültige Werte können bei der Verarbeitung schnell zu diesen Werten führen.
// Sichere Datenverarbeitung in Astro
async function fetchAndProcessData() {
const response = await fetch('https://api.example.com/data');
const rawData = await response.json();
// Validierung und Sanitisierung
const processedData = rawData.map(item => ({
id: item.id,
// Fallback auf 0 wenn der Wert nicht valide ist
price: Number.isFinite(Number(item.price)) ? Number(item.price) : 0,
// Explizite Null-Checks
quantity: item.quantity ?? 0,
// Berechnung nur mit validen Werten
total: calculateTotal(item.price, item.quantity)
}));
return processedData;
}
function calculateTotal(price, quantity) {
const numPrice = Number(price) || 0;
const numQuantity = Number(quantity) || 0;
const result = numPrice * numQuantity;
return Number.isFinite(result) ? result : 0;
}
Baut Validierung direkt in eure Datenverarbeitungs-Pipeline ein. Bei Never Code Alone empfehlen wir, dies als festen Bestandteil der Architektur zu etablieren, nicht als nachträglichen Fix.
7. Wie konfiguriere ich TypeScript für besseren Schutz vor NaN?
TypeScript allein kann NaN und Infinity nicht verhindern, da beide zum Type number gehören. Aber ihr könnt mit strikteren Typen und Runtime-Validierung eine zusätzliche Schutzschicht einbauen.
// Branded Type für validierte Zahlen
type FiniteNumber = number & { readonly __brand: 'finite' };
function toFiniteNumber(value: unknown): FiniteNumber {
const num = Number(value);
if (!Number.isFinite(num)) {
throw new Error(`Ungültiger numerischer Wert: ${value}`);
}
return num as FiniteNumber;
}
// Verwendung mit Astro DB
import { db, Products } from 'astro:db';
async function insertProduct(name: string, rawPrice: unknown) {
const price = toFiniteNumber(rawPrice);
await db.insert(Products).values({
name,
price // TypeScript weiß: das ist eine validierte Zahl
});
}
Diese Kombination aus TypeScript-Typen und Runtime-Validierung gibt euch das Beste aus beiden Welten: Compile-Time-Sicherheit und Laufzeit-Schutz.
8. Welche Best Practices gelten für Formular-Eingaben mit numerischen Werten?
Formular-Eingaben kommen immer als Strings an, und die Konvertierung zu Zahlen ist eine häufige Fehlerquelle. HTML5-Input-Typen helfen, sind aber kein vollständiger Schutz.
// Astro-Komponente mit sicherer Formular-Verarbeitung
---
export const prerender = false;
if (Astro.request.method === 'POST') {
const formData = await Astro.request.formData();
// Sichere Konvertierung
function parseFormNumber(value: FormDataEntryValue | null): number {
if (value === null || value === '') return 0;
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : 0;
}
const quantity = parseFormNumber(formData.get('quantity'));
const price = parseFormNumber(formData.get('price'));
// Jetzt sicher für Astro DB
await db.insert(Orders).values({ quantity, price });
}
---
<form method="POST">
<input type="number" name="quantity" step="1" min="0" required />
<input type="number" name="price" step="0.01" min="0" required />
<button type="submit">Speichern</button>
</form>
Verlasst euch niemals allein auf Client-seitige Validierung. Die Server-seitige Prüfung ist unverzichtbar, da HTML-Attribute umgangen werden können.
9. Wie behandle ich Division und mathematische Operationen sicher?
Division ist die klassische Quelle für Infinity-Werte. Jede Division durch eine Variable, die potenziell Null sein könnte, braucht eine Schutzprüfung.
// Unsichere Division
function calculateAverage(total, count) {
return total / count; // Gefahr: count könnte 0 sein!
}
// Sichere Division
function safeCalculateAverage(total, count) {
if (!Number.isFinite(total) || !Number.isFinite(count)) {
return 0; // oder throw, je nach Anforderung
}
if (count === 0) {
return 0; // Explizite Behandlung von Division durch Null
}
const result = total / count;
return Number.isFinite(result) ? result : 0;
}
// Utility für sichere mathematische Operationen
const SafeMath = {
divide(a, b, fallback = 0) {
if (!Number.isFinite(a) || !Number.isFinite(b) || b === 0) {
return fallback;
}
return a / b;
},
percentage(value, total, fallback = 0) {
return this.divide(value * 100, total, fallback);
}
};
Erstellt euch eine kleine Utility-Bibliothek für mathematische Operationen. Das vereinheitlicht die Fehlerbehandlung im gesamten Projekt.
10. Wie implementiere ich eine globale Validierungsschicht für Astro DB?
Der eleganteste Ansatz ist eine zentrale Validierungsschicht, die alle Datenbank-Operationen absichert. So müsst ihr nicht bei jeder einzelnen Abfrage an die Validierung denken.
// lib/db-utils.ts
import { db } from 'astro:db';
type RecordValue = string | number | boolean | null | Date;
type RecordObject = Record<string, RecordValue>;
function sanitizeValue(value: RecordValue): RecordValue {
if (typeof value === 'number') {
if (!Number.isFinite(value)) {
console.warn('Ungültiger numerischer Wert ersetzt:', value);
return 0;
}
}
return value;
}
function sanitizeRecord<T extends RecordObject>(record: T): T {
const sanitized = {} as T;
for (const [key, value] of Object.entries(record)) {
sanitized[key as keyof T] = sanitizeValue(value) as T[keyof T];
}
return sanitized;
}
// Wrapper für sichere Inserts
export async function safeInsert<T extends RecordObject>(
table: any,
values: T
) {
const sanitizedValues = sanitizeRecord(values);
return db.insert(table).values(sanitizedValues);
}
// Verwendung
import { safeInsert } from '../lib/db-utils';
import { Products } from 'astro:db';
await safeInsert(Products, {
name: 'Testprodukt',
price: userInput // Wird automatisch validiert
});
Diese Architektur schützt euch auch dann, wenn mal jemand vergisst, einzelne Werte zu validieren. Sprecht uns an, wenn ihr Unterstützung bei der Implementierung solcher Patterns braucht – wir haben bei Never Code Alone langjährige Erfahrung mit robusten Datenarchitekturen.
Fazit
Der „Only finite numbers“-Fehler in Astro ist kein Bug, sondern ein Schutz vor Datenqualitätsproblemen. Mit den richtigen Validierungsmustern und einer durchdachten Architektur könnt ihr diese Fehler zuverlässig vermeiden.
Die wichtigsten Punkte zusammengefasst: Nutzt Number.isFinite() für alle numerischen Validierungen, behandelt externe Daten grundsätzlich als nicht vertrauenswürdig, und baut eine zentrale Validierungsschicht für eure Datenbank-Operationen.
Habt ihr Fragen zu Astro, TypeScript oder allgemein zur Softwarequalität? Wir freuen uns auf eure Nachricht!
Kontakt: roland@nevercodealone.de
Never Code Alone – Über 15 Jahre spezialisiert auf Softwarequalität, Open Source und Remote Consulting.
