Reference

Errors

Every exported error value in collage, grouped by where it comes from, with what it means and what to do about it.

collage reports failures with sentinel error values, exported from pkg/collage, and wraps them with the details — the page, the path, the field. Match them with errors.Is, never by comparing messages:

if err := app.RegisterPage(page); errors.Is(err, collage.ErrDuplicateRoute) {
	// two pages claim one path
}

Most of them are reported at startup: New validates the configuration and parses every template, registration validates every page, and starting the application checks what only the whole set can reveal. A mistake in how the site is put together is a program that refuses to start, not a page that fails for the first reader who finds it.

The tables below are grouped by where each error comes from. The message is the text the sentinel carries before any wrapping adds detail.

Since v0.10.0 every error below is exported. Before it, the action, request-forgery, method, asset, {{dict}} and template-escapes-root errors, and ErrNotStatic, existed but could only be told apart by their messages. (ErrTemplateRootMissing was exported already.)

Configuration

Returned by collage.New, from Config.Validate or while building the application. See Configuration.

Error Message Means What to do
ErrNilConfig collage: nil config New(nil). Pass a *Config; its zero value is fine.
ErrInvalidPort collage: invalid port Server.Port is outside 1–65535. Leave it zero for 3000, or set a valid port.
ErrEmptyTemplateRoot collage: empty template root Template.Root is empty and Template.FS is nil. Only reachable by calling Validate yourself; New defaults Root first.
ErrTemplateRootMissing collage: template root missing Template.Root does not exist or is not a directory. The most common startup failure: check the working directory, or embed the templates.
ErrTemplateEscapesRoot collage: template escapes root A template under Template.Root resolves outside it — a symlink leading out of the directory. Copy the file in rather than linking to it.
ErrInvalidCacheType collage: invalid cache type Cache.Enabled, no Store, and Type is neither "memory" nor "disk". Fix the spelling, or supply a Store.
ErrEmptyCacheDir collage: disk cache needs a directory Cache.Type is "disk" and Cache.Dir is empty. Set Dir.
ErrEmptyCacheVersion collage: disk cache needs a version A disk cache was built with no version. Normally unreachable: an empty Version is derived from the binary.
ErrUnsupportedCache collage: unsupported cache type The cache type names nothing the framework can build. Normally caught earlier as ErrInvalidCacheType.
ErrEmptyLocaleDefault collage: empty default locale Locale.Default is empty. Only reachable through Validate; New defaults it to "en".
ErrLocaleDefaultNotSupported collage: default locale not in supported locales Locale.Supported does not include Locale.Default. Add the default to Supported.
ErrNegativeDuration collage: negative duration One of the six duration fields is negative; the message names which. Use zero for the default.

Plugins and commands

Error Message Means What to do
ErrNilPlugin collage: nil plugin A nil plugin was registered. —
ErrEmptyPluginName collage: empty plugin name A plugin's Name() is empty. Give it a name like acme/stamp.
ErrDuplicatePlugin collage: duplicate plugin Two plugins share a name. Register each plugin once.
ErrConfigurerRegisteredLate collage: plugin needs Configure and must be supplied in Config.Plugins RegisterPlugin was given a plugin with a Configure phase, which has already passed. Move it to Config.Plugins.
ErrDuplicateTemplateFunc collage: duplicate plugin template function AddTemplateFunc was called for a name already added — by another plugin, or by the same one a second time. AddTemplateFunc returns it to the plugin's Configure; New fails only if Configure returns it. The plugins conflict: Template.Funcs cannot prevent it, so drop or rename one of them.
ErrUnknownPluginConfig collage: plugin configuration names no registered plugin A PluginConfig key matches no registered plugin. Checked when the application starts. Almost always a typo in the key.
ErrEmptyCommandName collage: empty command name RegisterCommand with no name. —
ErrDuplicateCommand collage: duplicate command name Two commands share a name. —
ErrNilApp collage: nil app DispatchCommands was given a nil *App. —
ErrUnknownCommand collage: unknown command DispatchCommands got no arguments, or a name no plugin registered. The scaffolded main.go exits 2 on it, as a usage error; a program that would rather serve can fall through on it instead.

See Writing a plugin.

Fragments and pages

Two places report these. A few are recorded by the builders as the chain runs — ErrDuplicateSlot, ErrUnknownSlot and ErrSlotResolved from WithSlot, WithSlotResolver and WithSlotFragment (which also records Bind's ErrNilFragment and ErrSlotOccupied), ErrInvalidTimeout from WithTimeout, ErrMissingContent from a page's Build, and ErrNoDocumentHandler from a document's — and you can read them with BuildErr(). What a builder recorded stays on the value it built, and RegisterPage and RegisterDocument refuse a value carrying any — a page's own, or those of any fragment in its tree — wrapped as collage: page %q was built with errors: %w (collage: document %q was built with errors: %w for a document), whether or not BuildErr() was called.

The rest are found by validation when the page is registered: RegisterPage checks every fragment in the tree, its names, templates, slots, timeouts, TTLs, paths and error pages, and returns the first failure. A fragment opened with WithFragmentPath is part of the page for this (since v0.11.0): its template, its builder's mistakes and its validation are checked at registration like the rest. Either way a malformed page is refused before it serves anything.

Error Message Means
ErrEmptyName collage: empty name A fragment or page has no name.
ErrEmptyTemplatePath collage: empty template path A fragment names no template.
ErrNilFragment collage: nil fragment A nil fragment was used where one is required — bound to a slot, or returned by a slot resolver.
ErrDuplicateSlot collage: slot already declared WithSlot was called twice with one name.
ErrUnknownSlot collage: unknown slot A fragment was bound to, or a template called {{slot}} for, a slot the fragment never declared.
ErrInvalidSlotDefinition collage: invalid slot definition A slot has an empty name, or a map key that does not match its own name.
ErrSlotOccupied collage: slot already occupied A second fragment was bound to a slot that holds one — or a resolver returned several for it.
ErrSlotResolved collage: slot is filled by a resolver One slot was given both a resolver and bound fragments.
ErrRequiredSlotUnfilled collage: required slot has no fill A slot declared required has nothing bound to it.
ErrFragmentCycle collage: fragment cycle detected A fragment is reachable from itself.
ErrMissingContent collage: missing content A page has no content fragment.
ErrInvalidTimeout collage: invalid timeout A fragment's timeout is negative.
ErrMissingTTL collage: missing cache ttl for incremental strategy Incremental was given a zero TTL.
ErrInvalidTTL collage: invalid cache ttl A page's TTL is negative.
ErrInvalidPath collage: invalid path A path pattern does not start with /.
ErrInvalidRedirectStatus collage: invalid redirect status code A redirect status other than 0, 301, 302, 307 or 308.
ErrSelfErrorPage collage: page cannot reference itself as an error page A page is its own not-found or error page.

See Pages and layouts and Fragments and slots.

Registration and routing

Returned by RegisterPage, RegisterNotFoundPage, RegisterErrorPage and RegisterDocument, or when the application starts.

Error Message Means What to do
ErrAppStarted collage: application already started A registration method was called after the application started — including RegisterPlugin after any start that failed (since v0.12.0; after one that failed in a plugin's Init since v0.11.0). Register everything before Handler, ListenAndServe, Start, RenderPath or DispatchCommands.
ErrNilPage collage: nil page A nil page was registered. —
ErrDuplicatePage collage: duplicate page name Two pages share a name. Names are how links find pages; make them unique.
ErrTemplateNotFound collage: template not found A page's fragment names a template that was not loaded. Check the path relative to Template.Root, extension included.
ErrUnregisteredErrorPage collage: error page not registered A page names a not-found or error page that was never registered. Checked at start. Register it with RegisterNotFoundPage or RegisterErrorPage; an unregistered one would render empty when needed.
ErrInvalidPattern collage: invalid pattern A path or redirect source is malformed: no leading /, an empty segment, an empty placeholder name, a catch-all that is not last, or — since v0.11.0 — a placeholder inside a segment, such as /feeds/{category}.xml. Fix the pattern. A placeholder is a whole segment: /feeds/{category}/rss.xml.
ErrDuplicateRoute collage: duplicate route A path or redirect source is already registered in that locale. —
ErrAmbiguousParameterName collage: ambiguous parameter name Two patterns use different parameter names at one position, such as /blog/{slug} and /blog/{id}/edit. Use one name at that position.
ErrRedirectShadowsPage collage: redirect shadows a registered page A redirect's source is also a page's path. One of the two would be unreachable; remove one.
ErrUnsubstitutedPlaceholder collage: redirect placeholder not captured by from pattern A redirect's destination uses a {name} its source does not capture. Capture it in the source, or remove it.

Documents

Error Message Means
ErrNilDocument collage: nil document A nil document was registered.
ErrEmptyContentType collage: empty content type A document declares no content type. It is required and never guessed.
ErrNoDocumentHandler collage: document has no handler A document has no handler. Unlike a page, it has no template to fall back on.
ErrDuplicateDocument collage: duplicate document name Two documents share a name.
ErrDocumentNotFound collage: no document at path RenderDocumentPath found no document at the path — including when a page or a redirect is there.
ErrEmptyDocumentBody collage: document handler produced an empty body A handler succeeded with an empty body: a 500 when served, and not written by a build. A handler that really means "empty" can return a single newline.

See Documents.

Mounts and handlers

Error Message Means
ErrUnknownAsset collage: unknown asset rc.Asset, rc.HoistStylesheet, {{asset}} or {{stylesheet}} was given a path no mount serves. In a template, the render fails.
ErrNoMountForAsset collage: no mount serves that asset Wrapped inside ErrUnknownAsset, when no mount's prefix covers the path at all — as opposed to a mount that has no such file.
ErrInvalidPrefix collage: invalid mount prefix A mount prefix does not begin and end with /, is / alone, or begins with //. A mount at / would swallow every route.
ErrNilFS collage: nil mount file system A mount was given no filesystem.
ErrMountConflict collage: mount prefixes overlap Two mounts — or a mount and an App.Handle prefix — claim overlapping prefixes.
ErrMountShadowsRoute collage: mount shadows a route A mount prefix, or an App.Handle prefix, would swallow a route's path — a page's, a document's, a redirect's or an action's. Checked at start, whatever the registration order.
ErrInvalidHandlerPrefix collage: handler prefix must begin and end with "/" and not be "/" App.Handle was given a bad prefix.
ErrNilHandler collage: nil handler App.Handle or App.Use was given nothing to run.

See Static assets and Middleware and your own API.

Rendering

Error Message Means What to do
ErrNotFound collage: not found You return this one. A data handler that wraps it says the content does not exist, rather than failed to load. fmt.Errorf("post %q: %w", slug, collage.ErrNotFound) makes a required fragment's failure a 404 with the not-found page, not a 500.
ErrRequiredSlotEmpty collage: required slot is empty At render time, a required slot holds nothing — typically a resolver returned no fragments. Subject to the fragment's failure policy.
ErrMaxDepthExceeded collage: max fragment depth exceeded The fragment tree nests deeper than the engine allows. Almost always a fragment bound into its own slot, directly or not.
ErrNoRootFragment collage: page has no root fragment A page has neither a layout nor content. —
ErrPageNotFound collage: no page at path App.RenderPath found no page at the path. —
ErrOnceTypeMismatch collage: once key fetched as two different types Two collage.Once calls asked for one key as different types in one render. The keys collide; namespace them.
ErrCachedTypeMismatch collage: Cached key holds a value of a different type Two collage.Cached calls asked for one key as different types. As above.
ErrDictOddArgs collage: dict requires an even number of arguments {{dict}} was given a key with no value. Pair every key with a value.
ErrDictKeyNotString collage: dict key must be a string A {{dict}} key is not a string. Quote the key.
ErrCSRFDisabled collage: csrfToken used but request-forgery protection is disabled A template calls {{csrfToken}} in an application with Security.DisableCSRF set. Remove the call, or turn protection back on.

A panic in a data handler, a slot resolver or a template function does not take the process down: it becomes a collage.PanicError, and the fragment fails like any other. Reach it with errors.As to recover the panic value and its stack:

var panicked *collage.PanicError
if errors.As(err, &panicked) {
	log.Printf("panic: %v", panicked.Value)
}

See Data handlers for how a failure becomes a 404, a 500, a fallback or nothing.

Returned by App.URL and failed renders from {{pageURL}}, {{pageURLIn}} and {{localeURL}}. See Links and locales.

Error Message Means
ErrUnknownRoute collage: no page or document by that name No page or document is registered under the name — or both are, and the link is ambiguous.
ErrNoPathInLocale collage: no path in that locale The route has no path in the locale asked for. {{pageURL}} falls back to the default locale instead, and {{localeURL}} renders the empty string.
ErrRouteParams collage: route parameters do not match the pattern A parameter is missing or empty, names no placeholder, is . or .., or the template passed an odd number of arguments.
ErrLocaleUnreachable collage: no URL reaches that locale The locale is not in Locale.Supported, or it is not the default and path locales are disabled.

Actions

Returned by RegisterAction. RegisterPage checks an action attached to a page too — ErrNilAction, ErrNoMethods, and since v0.10.0 ErrNoActionHandler and ErrDuplicateAction — and refuses a nil fragment path with ErrNilFragmentPath. Since v0.11.0 there is one ErrNoActionHandler, the same value at registration and on a request.

Error Message Means What to do
ErrNilAction collage: nil action A nil action was registered, or attached to a page. —
ErrEmptyActionName collage: action has no name An action has no name. Give it one; it names the action in logs and errors.
ErrDuplicateAction collage: duplicate action A second action was registered under a name already taken. —
ErrNoActionPaths collage: action has no paths A standalone action has no WithPath. An action on a page takes the page's paths; one on its own needs its own.
ErrNoActionHandler collage: action has no handler An action has no WithHandler. —
ErrNoMethods collage: action declares no methods An action answers no method. WithMethods(http.MethodPost), or WithAction on a page.
ErrNilFragmentPath collage: fragment path has no fragment WithFragmentPath was given a nil fragment. —
ErrUnregisteredPage collage: action answered with a page that was never registered An action's RenderPage returned a page that was not registered. The request fails with a 500. Register the page, and answer with that same value rather than building one in the handler.

See Forms and actions.

Vary and SkipCache

Returned by collage.Vary and collage.SkipCache, which must be called from middleware. See Caching and Previews.

Error Message Means What to do
ErrVaryTooLate collage: Vary or SkipCache called after routing; call it from middleware Vary or SkipCache was called after routing began — from a data handler, say. Since v0.11.0 on every route; before, only on a cached page, and a late call elsewhere did nothing. Call it from middleware registered with App.Use.
ErrVaryOutsideRequest collage: Vary called on a request collage is not serving Vary or SkipCache was called on a request that did not come through collage's handler. —

Request forgery

A submission that fails the forgery check is answered with a 403 before the action's handler runs, and error hooks receive the reason under the stage "route", wrapped with the action's name:

Error Message Means
ErrCSRFMissing collage: no csrf token The submission carried no token, or no cookie.
ErrCSRFMismatch collage: csrf token does not match The token is not the one in the cookie.
ErrCSRFInvalid collage: csrf token is not valid The token was not signed with this application's key.

The usual causes are a form with no {{csrfToken}}, and a key generated per process — set Security.CSRFKey so tokens survive restarts and work across instances. A body over the size limit is a 413 instead, even when reading the token is what hit the limit. See Forms and actions.

{{csrfToken}} in an application with Security.DisableCSRF set is ErrCSRFDisabled; see Rendering.

Reported to error hooks

These reach a plugin's OnError in ErrorEvent.Err, so it can tell failures apart without reading messages. See Writing a plugin.

Error Message Stage Means
ErrNoRoute collage: no route matched the request not_found No route matched the request — a link or routing problem. Deliberately not ErrNotFound: both are a 404, and they have different causes.
ErrNotFound see Rendering render A required fragment's content does not exist — a content problem.
ErrMethodNotAllowed collage: method not allowed route The path exists but answers no such method: a 405, with an Allow header naming what it does answer. On a document's URL the 405 is plain text (since v0.11.0).
ErrEmptyRender collage: page rendered no markup render A page rendered successfully but produced no markup, served or answered by an action: a 500. The same sentinel a static build records.
ErrCSRFMissing, ErrCSRFMismatch, ErrCSRFInvalid see above route A submission refused by the forgery check.
ErrEmptyErrorPage collage: error page rendered empty error_page A registered error page rendered successfully but produced no markup, so the built-in page was served instead.
ErrPanic collage: panic recovered while serving the request panic Something panicked while serving — a Cache, Metrics or Tracer implementation, a router, a plugin hook — and was recovered into a 500. Panics in data handlers and templates are PanicError instead.
ErrAssetFailed collage: asset request failed asset A mounted file request answered with a status of 400 or above: one sentinel for every such status.
ErrHandlerFailed collage: mounted handler failed handler A handler mounted with App.Handle answered with a server error.
ErrUnsafeRedirectTarget collage: unsafe redirect target route A redirect's destination, after substitution, is not a single-slash relative path — //host, /\host, or one with a control character. Answered with a 500, not a Location header.

"error_page" is the stage worth alerting on: the page that reports failures failed, and the reader still saw a plausible page, so nothing else would tell you.

Static builds

Returned by collage.NewBuilder and Builder.Build, or recorded in the BuildReport. See Static export.

Error Message Where Means
ErrNilRenderer collage: nil renderer NewBuilder The app is nil.
ErrInvalidOutDir collage: invalid output directory NewBuilder BuildOptions.OutDir is empty.
ErrDangerousOutDir collage: refusing to use a dangerous output directory Build OutDir resolves to a filesystem root — or, with Clean, to a repository root.
ErrOutputPathCollision collage: two builds target one output path Build Two pages would be written to one file — patterns differing only by a trailing slash, or a path provider returning a path twice. Reported before any page renders, and then no page is: documents, 404.html and assets are still written.
ErrPathEscapesOutDir collage: resolved path escapes the output directory report error An output path, or a symlink on the way to it, leads outside OutDir. Checked before that one file is written; only that path fails.
ErrDynamicPathUnresolved collage: dynamic path pattern requires a path provider skip A page's or document's path has a {param} and there is no path provider.
ErrNotStatic collage: a Dynamic() route cannot be built statically skip A page or document is Dynamic(), so there is nothing to export.
ErrDuplicateOutputPath collage: two build tasks write the same output path skip Two document tasks resolve to one file — a DocumentPathProvider returning one path twice. The first is built, the rest skipped.
ErrDegradedRender collage: refusing to write a degraded render report error A page rendered with a failed fragment and AllowDegraded is off. No file is written.
ErrEmptyRender collage: page rendered no markup report error A page rendered no markup at all. Refused even with AllowDegraded. One sentinel with serving's, above.
ErrUnresolvedToken collage: refusing to write a page whose forgery token was never resolved report error, skip The not-found page carries a {{csrfToken}}: a report error. Any other page with one is skipped instead: it needs a server.
ErrBuildPanic collage: panic while building a page report error Rendering or writing one page panicked; the build recovered and went on with the rest.
ErrEmptyDocumentBody see Documents report error A document produced an empty body.

Report errors are in BuildReport.Errors, a slice of errors that match with errors.Is. A skip is a SkipRecord in BuildReport.Skipped: its Reason is a sentence for people, and its Err (since v0.10.0) is the sentinel for code — ErrNotStatic, ErrDynamicPathUnresolved, ErrUnresolvedToken or ErrDuplicateOutputPath — so match it with errors.Is(skip.Err, …) rather than by reading Reason.