#3792·atlas

goose format: statement line containing "Down" is treated as the Down boundary, truncating the statement

Author: Raymond-ChristopherCreated Sep 3, 2026Updated Sep 3, 2026

Summary

When reading a migration directory with format=goose, any statement line containing the case-sensitive token Down — e.g. product copy like 'Download report' inside a VALUES row — is treated as the -- +goose Down boundary. The line is dropped from the Up statement, which then fails to parse on apply/lint.

Repro (atlas v1.3.3-d7c803a-canary, also v1.3.3-140afb4 and v1.2.4)

20260903000001_demo.sql:

sql
-- +goose Up
CREATE TABLE items (id serial PRIMARY KEY, label text NOT NULL);

INSERT INTO items (label)
VALUES ('Download report')
ON CONFLICT DO NOTHING;

-- +goose Down
DROP TABLE items;
bash
$ atlas migrate hash --dir "file://.?format=goose"
$ atlas migrate apply --dir "file://.?format=goose" --url "postgres://postgres:pass@localhost:5499/demo?sslmode=disable"
...
Error: sql/migrate: executing statement "INSERT INTO items (label)\nON CONFLICT DO NOTHING;" from version "20260903000001": pq: syntax error at or near "ON" at position 2:1 (42601)

The executed statement shows the VALUES line was swallowed: INSERT INTO items (label)\nON CONFLICT DO NOTHING;.

Characterization

Same file, only the label changed:

label result
'Download report' truncated → 42601
'Downtime alert' truncated → 42601
'markdown guide' applies cleanly
'shut down now' applies cleanly

So the boundary match appears to be a case-sensitive substring/token match for Down on arbitrary statement lines, rather than requiring the -- +goose Down directive comment.

Expected

Only a -- +goose Down annotation line should end the Up section (goose itself applies this file correctly; so does golang-migrate on the equivalent split files).

Impact

Any seed/data migration whose content contains words like "Download" or "Downtime" fails migrate lint/migrate apply (and migrate push replay) with a false 42601, with no config escape we could find. We currently work around it with continue-on-error on the lint step in CI.