fix(untracked): stream include metadata null after update#69
Merged
lwargin-circle merged 11 commits intoApr 21, 2026
Conversation
…read-after-update
When updating a quicknode_stream resource, the provider calls readStreamFromAPI
(a GET) after the PATCH to refresh computed fields. For certain stream types the
QuickNode API does not include include_stream_metadata in the GET response.
Because readStreamFromAPI initialised a blank StreamResourceModel{} and only
populated fields that were present in the response, the field was left as null.
The Update function then assigned that null back to the plan, causing Terraform
to report "Provider produced inconsistent result after apply" for every affected
stream — even when the field itself was not part of the change.
Fix: add an optional fallback parameter to readStreamFromAPI. When the API
response omits include_stream_metadata, the fallback (plan) value is preserved
instead of letting the field become null. All existing callers are unaffected
(no fallback passed). The Update caller now passes &plan so any API-omitted
field retains its planned value.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The QuickNode GET /streams/:id endpoint no longer returns include_stream_metadata in its response (confirmed via curl; field also removed from official API docs). This caused two separate issues: 1. Read() — on every terraform plan/apply the field was read back as null from the API, overwriting the known state value and triggering a phantom diff that would attempt a no-op update on every cycle. 2. Update() — after a successful PATCH the provider refreshed state via the same GET call; the null field was then assigned to the plan, causing Terraform to fail with "Provider produced inconsistent result after apply". Fix: pass the current state (Read) or current plan (Update) as a fallback to readStreamFromAPI so that any field absent from the API response is preserved from the known-good value rather than silently becoming null. All other callers (Create, pre-update status check) remain unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
QuickNode silently removed include_stream_metadata from their Streams API: - No longer returned in GET /streams/:id responses (confirmed via curl) - No longer accepted in POST/PATCH request bodies (removed from live OpenAPI spec) - No longer documented in the official API docs This caused two Terraform failures for any stream that was updated: 1. "Provider produced inconsistent result after apply" — after a PATCH the provider called GET to refresh state; the absent field left a null in the freshly initialised model, overwriting the planned value of "header". 2. Phantom diffs — every terraform plan overwrote the state value with null, queuing a spurious update on every cycle. Changes in this commit: - Update vendored streams-openapi.json from the live QuickNode API endpoint (make vendor: curl https://api.quicknode.com/streams/rest/openapi.json) - Regenerate streams.gen.go — IncludeStreamMetadata removed from CreateStreamDto and UpdateStreamDto generated types - Remove IncludeStreamMetadata from Create and Update API request bodies in stream_resource.go (field no longer in API contract) - Mark schema field include_stream_metadata as Optional + deprecated so that existing configurations continue to parse without error while users migrate away from the field - Preserve fallback in readStreamFromAPI (Read + Update) so that existing state values are not silently nullified by the absent GET response field Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dependency ReviewThe following issues were found:
License Issuesgo.mod
.github/workflows/test.yml
Allowed Licenses: BSD-1-Clause, BSD-2-Clause, BSD-3-Clause, MIT, MIT-0, Apache-1.1, Apache-2.0, Artistic-1.0, Artistic-2.0, PHP-3.0, PHP-3.01, PSF-2.0, Zlib, zlib-acknowledgement, BSL-1.0, OpenSSL, WTFPL, CC0-1.0, CC-PDDC, CC-BY-1.0, CC-BY-2.0, CC-BY-2.5, CC-BY-3.0, CC-BY-4.0, Unlicense, ISC, BlueOak-1.0.0, BSD-2-Clause-Patent, ADSL, Apache-2.0, APAFML, BSD-1-Clause, BSD-2-Clause, BSD-2-Clause-FreeBSD, BSD-2-Clause-NetBSD, BSD-2-Clause-Views, BSL-1.0, DSDP, ECL-1.0, ECL-2.0, ImageMagick, ISC, Linux-OpenIB, MIT, MIT-Modern-Variant, MS-PL, MulanPSL-1.0, Mup, PostgreSQL, Spencer-99, UPL-1.0, Xerox, 0BSD, AFL-1.1, AFL-1.2, AFL-2.0, AFL-2.1, AFL-3.0, AMDPLPA, AML, AMPAS, ANTLR-PD, ANTLR-PD-fallback, Apache-1.0, Apache-1.1, Artistic-2.0, Bahyph, Barr, BSD-3-Clause, BSD-3-Clause-Attribution, BSD-3-Clause-Clear, BSD-3-Clause-LBNL, BSD-3-Clause-Modification, BSD-3-Clause-No-Nuclear-License-2014, BSD-3-Clause-No-Nuclear-Warranty, BSD-3-Clause-Open-MPI, BSD-4-Clause, BSD-4-Clause-Shortened, BSD-4-Clause-UC, BSD-Source-Code, bzip2-1.0.5, bzip2-1.0.6, CC0-1.0, CNRI-Jython, CNRI-Python, CNRI-Python-GPL-Compatible, Cube, curl, eGenix, Entessa, FTL, HTMLTIDY, IBM-pibs, ICU, Info-ZIP, Intel, JasPer-2.0, Libpng, libpng-2.0, libtiff, LPPL-1.3c, MIT-0, MIT-advertising, MIT-open-group, MIT-CMU, MIT-enna, MIT-feh, MITNFA, MTLL, MulanPSL-2.0, Multics, Naumen, NCSA, Net-SNMP, NetCDF, NTP, OLDAP-2.0, OLDAP-2.0.1, OLDAP-2.1, OLDAP-2.2, OLDAP-2.2.1, OLDAP-2.2.2, OLDAP-2.3, OLDAP-2.4, OLDAP-2.5, OLDAP-2.6, OLDAP-2.7, OLDAP-2.8, OML, OpenSSL, PHP-3.0, PHP-3.01, Plexus, PSF-2.0, Python-2.0, Ruby, Saxpath, SGI-B-2.0, SMLNJ, SWL, TCL, TCP-wrappers, Unicode-DFS-2015, Unicode-DFS-2016, Unlicense, VSL-1.0, W3C, X11, XFree86-1.1, Xnet, xpp, Zlib, zlib-acknowledgement, ZPL-2.0, ZPL-2.1, AAL, Adobe-2006, Afmparse, Artistic-1.0, Artistic-1.0-cl8, Artistic-1.0-Perl, Beerware, blessing, Borceux, CECILL-B, ClArtistic, Condor-1.1, Crossword, CrystalStacker, diffmark, DOC, EFL-1.0, EFL-2.0, Fair, FSFUL, FSFULLR, Giftware, HPND, IJG, Leptonica, LPL-1.0, LPL-1.02, MirOS, mpich2, NASA-1.3, NBPL-1.0, Newsletr, NLPL, NRL, OGTSL, OLDAP-1.1, OLDAP-1.2, OLDAP-1.3, OLDAP-1.4, psutils, Qhull, Rdisc, RSA-MD, Spencer-86, Spencer-94, TU-Berlin-1.0, TU-Berlin-2.0, Vim, W3C-19980720, W3C-20150513, Wsuipa, WTFPL, xinetd, Zed, Zend-2.0, ZPL-1.1 Excluded from license check: pkg:golang/github.com/hashicorp/terraform-plugin-framework@v1.15.0, pkg:golang/github.com/hashicorp/terraform-plugin-go@v0.27.0, pkg:golang/github.com/hashicorp/terraform-registry-address@v0.2.5, pkg:golang/google.golang.org/protobuf, pkg:golang/golang.org/x/crypto, pkg:golang/golang.org/x/mod, pkg:golang/golang.org/x/net, pkg:golang/golang.org/x/sync, pkg:golang/golang.org/x/sys, pkg:golang/golang.org/x/text, pkg:golang/golang.org/x/time, pkg:golang/golang.org/x/tools, pkg:golang/honnef.co/go/tools OpenSSF Scorecard
Scanned Files
|
…eptance test Create() also called readStreamFromAPI without a fallback, causing include_stream_metadata to be overwritten with null after stream creation. Pass the plan as fallback so the config value is preserved in state. Update the acceptance test: - Remove TestCheckResourceAttr for include_stream_metadata (API no longer returns it, value comes from config fallback not API verification) - Add ImportStateVerifyIgnore for include_stream_metadata (import has no prior state to fall back to, so the field will be null after import) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pin aquasecurity/trivy-action to v0.35.0 so setup-trivy resolves (v0.2.2 tag removed). - Run tfplugindocs output for stream.md (include_stream_metadata optional/deprecated). Made-with: Cursor
setup-trivy uses install.sh which fetches binaries via get.trivy.dev; Circle hosted runners hit curl exit 6 (host resolve). Install the release tarball from github.com and skip the composite setup step. Made-with: Cursor
Resolves authorization bypass reported by Trivy/govulncheck so CI trivy-scan passes with exit-code 1. Made-with: Cursor
Code scanning UI is not available without GHAS; upload-sarif was misleading. Use scanners=vuln, exit-code 0 (non-blocking), upload SARIF as workflow artifact, and print a table to the job summary for review. Made-with: Cursor
8a9532b to
6dec937
Compare
Trivy reported LOW CVE in circl v1.6.1; fixed upstream in v1.6.3. Ignore local trivy-results.sarif; restore Trivy exit-code 1 on findings. Made-with: Cursor
google.golang.org/protobuf is BSD-3-Clause plus Google's golang patent grant; ScanCode reports it as incompatible without allowlisting, same as golang.org/x modules already listed here. Made-with: Cursor
Public workflow artifacts are downloadable by anyone; keep the job summary table for public repos and attach SARIF only when private. Made-with: Cursor
s2tu-circle
approved these changes
Apr 21, 2026
lwargin-circle
pushed a commit
that referenced
this pull request
Apr 21, 2026
🤖 I have created a release *beep* *boop* --- ## [0.7.2](v0.7.1...v0.7.2) (2026-04-21) ### Bug Fixes * **untracked:** stream include metadata null after update ([#69](#69)) ([8412cc4](8412cc4)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root Cause
QuickNode silently removed
include_stream_metadatafrom their Streams API — a breaking changewith no announcement:
/streams/:idresponseOur vendored
streams-openapi.jsonstill had the field (last regenerated Feb 2026), causingthe provider to send a field the API no longer accepts and expect a value the API never returns.
Failures
1.
terraform apply— "Provider produced inconsistent result after apply"Any update to a
quicknode_stream(e.g. changingnotification_email) triggered:.include_stream_metadata: was cty.StringVal("header"), but now null.
The provider did a GET after the PATCH to refresh state; the absent field left
nullin thefreshly initialised
StreamResourceModel{}, overwriting the planned"header".2.
terraform plan— phantom diffs on every runEvery
Read()call overwrote the state value withnull, queuing a spurious updateon every plan/apply cycle.
Changes
api/streams/streams-openapi.jsonmake vendor)api/streams/streams.gen.goIncludeStreamMetadataremoved fromCreateStreamDto/UpdateStreamDtointernal/provider/stream_resource.goRequired→Optional+ deprecation warning; fallback inReadand post-updateReadSchema change:
Required→Optional+ deprecatedExisting configs that still set
include_stream_metadata = "header"will:terraform planUsers can remove the field from their configs at their own pace.
Testing
go build ./...— compiles cleanlygo test ./internal/...— all tests pass