HeyPuter/puter · error · HttpError
${key} must be an integer between ${min} and ${max}
Error message
${key} must be an integer between ${min} and ${max} What it means
Thrown by VideoGenerationDriver.#assertWriteAccess when the resolved destination path is the filesystem root ('/') or its parent is root (the file would land as a direct child of root). Puter forbids writes at the root namespace level; output must live under a user-owned directory. This guard runs before the ACL check so a root destination fails fast with a clear 400 rather than a permission error.
Source
Thrown at extensions/appTelemetry.ts:49
min,
max,
fallback,
}: { key: string; min: number; max: number; fallback: number },
): number => {
if (value === undefined || value === null) return fallback;
const parsed =
typeof value === 'number'
? value
: typeof value === 'string' && value.trim() !== ''
? Number(value)
: NaN;
if (
!Number.isFinite(parsed) ||
!Number.isInteger(parsed) ||
parsed < min ||
parsed > max
) {
throw new HttpError(
400,
`${key} must be an integer between ${min} and ${max}`,
);
}
return parsed;
};
/**
* Driver exposing the `app-telemetry` interface.
*
* The `/drivers/call` permission gate checks
* `service:app-telemetry:ii:app-telemetry`, which every actor already holds via
* the blanket `service` grant (hardcoded-permissions.js +
* `default_implicit_user_app_permissions`). The real authorization — "is the
* caller the app owner?" — is enforced inside `get_users` below, exactly as v1
* did.
*/
export class AppTelemetryDriver extends PuterDriver {View on GitHub (pinned to 908ec23eda)
Solutions
- Pass a destination under a user-owned directory, e.g. `~/Videos/<name>.mp4` or an absolute app folder path.
- Validate the path client-side before the call: it must not be '/' and dirname(path) must not be '/'.
- If the path originates from user input, default it to a known folder (the user's home / a 'Videos' subdir) when blank.
- Log the resolved path at the call site to catch normalization bugs (e.g. trailing-slash or empty-string collapse).
Example fix
// before
await puter.ai.txt2video({ prompt, path: '/' });
await puter.ai.txt2video({ prompt, path: '' });
await puter.ai.txt2video({ prompt, path: '/clip.mp4' });
// after
await puter.ai.txt2video({ prompt, path: '~/Videos/clip.mp4' }); Defensive patterns
Strategy: validation
Validate before calling
import pathPosix from 'node:path/posix';
function assertNonRootDestination(p) {
const resolved = pathPosix.normalize(p ?? '/');
if (resolved === '/' || pathPosix.dirname(resolved) === '/') {
throw new Error(`Destination must not be root or a direct child of root: ${p}`);
}
return resolved;
}
// before submit
assertNonRootDestination(destPath); Type guard
function isNonRootPath(p) {
if (typeof p !== 'string' || p.trim() === '') return false;
const n = p.replace(/\/+$/, '') || '/';
if (n === '/') return false;
const slash = n.lastIndexOf('/');
return slash > 0; // has a non-root parent directory
} Try / catch
try { await puter.ai.txt2video({ prompt, path: dest }); }
catch (e) {
if (e?.code === 'cannot_write_to_root') { dest = `~/Videos/${name}.mp4`; /* retry */ }
else throw e;
} Prevention
- Always qualify video destinations with a user-owned folder prefix.
- Normalize and validate paths at the form boundary, not at the API call site only.
- Treat a blank path field as a missing required field.
When it happens
Trigger: Calling puter.ai.txt2video(...) / the video-generation driver with a destination `path` that resolves to '/' (e.g. empty string normalized to root) or to '/<filename>' with no parent directory component. Happens when the caller omits the directory portion or passes a user-supplied path that trims to root.
Common situations: Frontend uses an empty/default `path` field that normalizes to '/'; building the destination from untrusted input without appending a folder; migrating from a v1 API that tolerated root writes; misconfigured default-destination config value.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/443354319503807d.
Report an issue: GitHub.