Configure file reading limits

Updated Oct 16, 2026

The contents, linecount, hash, and digest template filters read files through a shared byte budget so a checkout entry cannot exhaust Netsuke's memory or CPU. The default budget is 8 MiB per read, matching the fetch() response limit.

The reading filters also refuse to follow a symlink as the final path component and reject anything that is not a regular file once opened, including FIFOs and device nodes. A symlinked directory used inside a path is unaffected; only the final entry is checked. On Windows the same refusal covers every reparse point, not only symlinks: junctions, volume mount points, and other tags such as deduplication or cloud placeholders are all rejected, including tags Windows may add later.

follow_symlinks=true waives that final-component refusal, and only that. The capability that anchors every read in the workspace is unaffected, so a link whose target is written as an absolute path is still refused with a diagnostic reporting that a path led outside the filesystem — even when the target is in fact inside the workspace. Relativity of the link target, not containment of the resolved path, is what the resolver tests. A template that reads through a relative-target link is the supported case; on Windows a junction cannot be one, because mklink records an absolute target and so is always refused under either policy. Templates that deliberately read through a final symlink can pass the opt-in to accept it:

{{ 'generated/version.txt' | contents(follow_symlinks=true) }}

A single call may lower the budget with max_bytes, but never raise it above the configured ceiling:

{{ 'fixtures/big.bin' | hash(max_bytes=1024) }}

Reads that exceed the budget fail with a diagnostic naming the path and the limit, never the file contents. Raise the operator budget when legitimate builds hash large artefacts; prefer per-call max_bytes narrowing when a manifest merely wants to bound one input.